Java多线程之synchronized关键字

一、synchronized锁住的不是代码块,是对象。
 1 /**
 2  * synchronized 对某个对象加锁
 3  */
 4 public class SynchronizedTest {
 5
 6     private int count = 10;
 7     private Object o = new Object();
 8
 9     private void method() {
10         synchronized (o) { //任何线程想执行下面这段代码都需要拿到o这把锁
11             count--;
12             System.out.println(Thread.currentThread().getName() + " count=" + count);
13         }
14     }
15
16 }

二、synchronized是可重入的。

 1 import java.util.concurrent.TimeUnit;
 2
 3 /**
 4  * 一个同步方法可以调用另外一个同步方法,一个线程已经拥有了某个对象锁,再次申请仍然会得到这把锁。
 5  * 也就是说synchronized是可重入的。
 6  */
 7 public class SynchronizedTest3 {
 8
 9     synchronized void m1() {
10         System.out.println(Thread.currentThread().getName() + " m1 start ...");
11         try {
12             TimeUnit.SECONDS.sleep(1);
13         } catch (InterruptedException e) {
14             e.printStackTrace();
15         }
16         m2();
17         System.out.println(Thread.currentThread().getName() + " m1 end ...");
18     }
19
20     synchronized void m2() {
21         System.out.println(Thread.currentThread().getName() + " m2 start ...");
22         try {
23             TimeUnit.SECONDS.sleep(2);
24         } catch (InterruptedException e) {
25             e.printStackTrace();
26         }
27         System.out.println(Thread.currentThread().getName() + " m2 end ...");
28     }
29
30     public static void main(String[] args) {
31
32         SynchronizedTest3 test = new SynchronizedTest3();
33         new Thread(() -> {
34             test.m1();
35         }, "t1").start();
36         new Thread(() -> {
37             test.m2();
38         }, "t2").start();
39
40     }
41
42 }
三、子类同步方法调用父类同步方法,这是可以的。
 1 import java.util.concurrent.TimeUnit;
 2
 3 /**
 4  * 子类调用父类同步方法,这是可以的
 5  */
 6 public class SynchronizedTest5 {
 7
 8     public static void main(String[] args) {
 9
10         Chinese chinese = new Chinese();
11         chinese.m();
12
13     }
14
15     static class Person {
16         synchronized void m() {
17             System.out.println("m start ...");
18             try {
19                 TimeUnit.SECONDS.sleep(2);
20             } catch (InterruptedException e) {
21                 e.printStackTrace();
22             }
23             System.out.println("m end ...");
24         }
25     }
26
27     static class Chinese extends Person {
28         @Override
29         synchronized void m() {
30             System.out.println("child m start ...");
31             super.m();
32             System.out.println("child m end ...");
33         }
34     }
35
36 }
 
四、synchronized遇到异常,线程会释放锁。
 1 import java.util.concurrent.TimeUnit;
 2
 3 /**
 4  * 多线程环境synchronized遇到异常,线程会释放锁
 5  */
 6 public class SynchronizedTest6 {
 7
 8     int count = 0;
 9
10     synchronized void m() {
11         System.out.println(Thread.currentThread().getName() + " start");
12         while (true) {
13             count++;
14             System.out.println(Thread.currentThread().getName() + " count=" + count);
15             try {
16                 TimeUnit.SECONDS.sleep(1);
17             } catch (InterruptedException e) {
18                 e.printStackTrace();
19             }
20             if(count == 5) {
21                 int i = 1/0; //此处会抛出异常,锁将被释放,想要锁不被释放,可以在这里进行catch,让循环继续.
22                 //java.lang.ArithmeticException: / by zero
23                 //解决办法: try-catch这个异常
24             }
25         }
26     }
27
28     public static void main(String[] args) {
29
30         SynchronizedTest6 test = new SynchronizedTest6();
31         Runnable r = new Runnable() {
32             @Override
33             public void run() {
34                 test.m();
35             }
36         };
37
38         new Thread(r, "线程1").start();
39
40         try {
41             TimeUnit.SECONDS.sleep(3);
42         } catch (InterruptedException e) {
43             e.printStackTrace();
44         }
45
46         new Thread(r, "线程2").start();
47
48     }
49
50 }
五、synchronized优化
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * synchronized优化
 * synchronized代码块包住的代码越少越好
 */
public class SynchronizedTest7 {

    int count = 0;

    synchronized void add() {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<1000; i++) {
            count++;
        }
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

     void add1() {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
         synchronized(this) {
             for(int i=0; i<1000; i++) {
                 count++;
             }
         }
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        SynchronizedTest7 test = new SynchronizedTest7();
        List<Thread> threads = new ArrayList<>(10);
        long start = System.currentTimeMillis();
        for(int i=0; i<10; i++) {
            threads.add(new Thread(() -> {
                test.add();
            }, "Thread" + i));
        }
        threads.forEach(t -> t.start());
        threads.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.currentTimeMillis();
        System.out.println("add方法耗时:" + (end - start) + " count=" + test.count);

        //add1方法
        threads.clear();
        start = System.currentTimeMillis();
        for(int i=0; i<10; i++) {
            threads.add(new Thread(() -> {
                test.add1();
            }, "Thread" + i));
        }
        threads.forEach(t -> t.start());
        threads.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        end = System.currentTimeMillis();
        System.out.println("add1方法耗时:" + (end - start) + " count=" + test.count);

        ExecutorService service = Executors.newFixedThreadPool(10);
        start = System.currentTimeMillis();
        for(int i=0; i<10; i++) {
            service.submit(() -> {
                test.add();
            });
        }
        while (true) {
            if(!service.isTerminated()) break;
        }
        end = System.currentTimeMillis();
        System.out.println("ExecutorService add方法耗时:" + (end - start) + " count=" + test.count);
        service.shutdown();
//        if(service.isTerminated()) {
//            end = System.currentTimeMillis();
//            System.out.println("ExecutorService add方法耗时:" + (end - start) + " count=" + test.count);
//        }

        ExecutorService service1 = Executors.newFixedThreadPool(10);
        start = System.currentTimeMillis();
        for(int i=0; i<10; i++) {
            service1.submit(() -> {
                test.add1();
            });
        }
        while (true) {
            if(!service1.isTerminated()) break;
        }
        end = System.currentTimeMillis();
        System.out.println("ExecutorService add1方法耗时:" + (end - start) + " count=" + test.count);
        service1.shutdown();
//        if(service1.isTerminated()) {
//            end = System.currentTimeMillis();
//            System.out.println("ExecutorService add1方法耗时:" + (end - start) + " count=" + test.count);
//        }
    }

}
六、不要以字符串常量作为锁定对象
 1 /**
 2  * 不要以字符串常量作为锁定对象
 3  * str1和str2是同一个都对象
 4  * 会发生诡异的死锁阻塞
 5  */
 6 public class SynchronizedTest9 {
 7
 8     String str1 = "Hello";
 9     String str2 = "Hello";
10
11     void m1() {
12         synchronized (str1) {
13
14         }
15     }
16
17     void m2() {
18         synchronized (str2) {
19
20         }
21     }
22
23 }
 
 
七、synchronized写法
 1 public class SynchronizedTest2 {
 2
 3     private static int count = 10;
 4
 5     private synchronized void method() { //等同于synchronized(this)
 6         count--;
 7         System.out.println(Thread.currentThread().getName() + " count=" + count);
 8     }
 9
10     private static void method2() {
11         synchronized (SynchronizedTest2.class) { //考虑一下这里写synchronized(this)是否可以?
12             count--;
13         }
14     }
15
16 }
 
 

原文地址:https://www.cnblogs.com/mxh-java/p/12246413.html

时间: 2024-10-13 10:54:59

Java多线程之synchronized关键字的相关文章

JAVA多线程之Synchronized关键字--对象锁的特点

一,介绍 本文介绍JAVA多线程中的synchronized关键字作为对象锁的特点. 二,分析 synchronized可以修饰实例方法,如下形式: 1 public class MyObject { 2 3 synchronized public void methodA() { 4 //do something.... 5 } 这里,synchronized 关键字锁住的是当前对象.这也是称为对象锁的原因. 为啥锁住当前对象?因为 methodA()是个实例方法,要想执行methodA(),

java多线程之volatile关键字

在java线程并发处理中,关键字volatile的主要作用是使变量在多个线程间可见.那么volatile到底该怎么用了?我们首先来看一段代码: public class MyThread1 implements Runnable { private boolean istag = true; public boolean isIstag() { return istag; } public void setIstag(boolean istag) { this.istag = istag; }

Java多线程之synchronized和volatile的比较

概述 在做多线程并发处理时,经常需要对资源进行可见性访问和互斥同步操作.有时候,我们可能从前辈那里得知我们需要对资源进行 volatile 或是 synchronized 关键字修饰处理.可是,我们却不知道这两者之间的区别,我们无法分辨在什么时候应该使用哪一个关键字.本文就针对这个问题,展开讨论. 版权说明 著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 本文作者:Coding-Naga 发表日期: 2016年4月5日 本文链接:http://blog.csdn.net/

Java多线程之synchronized(一)

在上节中已经说过了“非线程安全”是如何出现的,链接如下:http://www.cnblogs.com/chentong/p/5650137.html,那么怎么解决“非线程安全”问题呢,只需要在两个线程都需要同时访问的方法前面加上synchronized关键字即可,我只贴出需要修改的这个方法的代码,具体修改如下: public static class GetNum { private int num = 0; //两个线程访问同一个对象中的同步方法时一定是线程安全的 synchronized p

JAVA多线程之Synchronize 关键字原理

image 众所周知 Synchronize 关键字是解决并发问题常用解决方案,有以下三种使用方式: 同步普通方法,锁的是当前对象. 同步静态方法,锁的是当前 Class 对象. 同步块,锁的是 {} 中的对象. 实现原理: JVM 是通过进入.退出对象监视器( Monitor )来实现对方法.同步块的同步的. 具体实现是在编译之后在同步方法调用前加入一个 monitor.enter 指令,在退出方法和异常处插入 monitor.exit 的指令. 其本质就是对一个对象监视器( Monitor

Java多线程之synchronized及其优化

Synchronized和同步阻塞synchronized是jvm提供的同步和锁机制,与之对应的是jdk层面的J.U.C提供的基于AbstractQueuedSynchronizer的并发组件.synchronized提供的是互斥同步,互斥同步是指在多个线程并发访问共享数据时,保证共享数据在同一时刻只有一个线程访问. 在jvm中,被synchronized修饰的代码块经javac编译之后,会在代码块前后分别生成一条monitorenter和moniterexit字节码指令,这两个字节码都需要一个

java多线程之synchronized

首先来看下一个场景,某电影院某个时间4个窗口同时在卖票,本场电影总共票只有100张,卖完为止.看下实际代码. package cn.com.thread; public class TestThread { public static void main(String[] args) { SellTicketThread t=new SellTicketThread(); new Thread(t,"窗口1").start(); new Thread(t,"窗口2"

Java多线程之synchronized(二)

为了解决“非线程安全”带来的问题,上一节中使用的办法是用关键字synchronized修饰多个线程可能同时访问到的方法,但是这样写是存在一定的弊端的,比如线程A调用一个用synchronized修饰的同步方法,这个方法要执行很长时间,那么其它的线程必须无条件的等线程A执行完释放掉对象锁,当然前提是其他的线程也要访问这个同步方法.这种情况就可以用synchronized代码块来解决.在解决之前我先附上一段没优化之前的方法,这样就可以直观的看到效果差异. 证明synchronized方法的弊端,代码

Java多线程之synchronized(五)

上篇介绍了用synchronized修饰static方式来实现“Class 锁”,今天要介绍另一种实现方式,synchronized(class)代码块,写法不一样但是作用是一样的.下面我附上一段代码来看一下synchronized(class)代码块的基本用法,如下: public static void main(String[] args) { Service4 s1 = new Service4(); Service4 s2 = new Service4(); ThreadA a = n