Java synchronized关键字用法(清晰易懂)

本篇随笔主要介绍 java 中 synchronized 关键字常用法,主要有以下四个方面:

  1、实例方法同步

  2、静态方法同步

  3、实例方法中同步块

  4、静态方法中同步块

  

  我觉得在学习synchronized关键字之前,我们首先需要知道以下一点:Java 中每个实例对象对应一把锁且每个实例对象只有一把锁,synchronized 关键字是通过对相应的实例对象加锁来实现同步功能的。

  

  一、实例方法中使用 synchronized 加锁

  实例方法中默认被加锁的对象是调用此方法的实例对象。

  

 1 class ImmutableValue {
 2     public synchronized void comeIn() throws InterruptedException{
 3         System.out.println(Thread.currentThread().getName() + ": start");
 4         Thread.sleep(5000);
 5         System.out.println(Thread.currentThread().getName() + ": finish");
 6     }
 7     public  void synchronized comeInIn() throws InterruptedException {
 8         System.out.println(Thread.currentThread().getName() + ": start");
 9         Thread.sleep(5000);
10         System.out.println(Thread.currentThread().getName() + ": finish");
11     }
12 }
13 public class TestImmutableValue {
14     public static void main(String[] args) {
15         ImmutableValue im = new ImmutableValue();
16         Thread t1 = new Thread(new Runnable() {
17
18             @Override
19             public void run() {
20                 // TODO Auto-generated method stub
21                 try {
22                     im.comeIn();
23                 } catch (InterruptedException e) {
24                     // TODO Auto-generated catch block
25                     e.printStackTrace();
26                 }
27             }
28
29         }, "t1");
30         Thread t2 = new Thread(new Runnable() {
31
32             @Override
33             public void run() {
34                 // TODO Auto-generated method stub
35                 try {
36                     im.comeInIn();
37                 } catch (InterruptedException e) {
38                     // TODO Auto-generated catch block
39                     e.printStackTrace();
40                 }
41             }
42
43         }, "t2");
44         t1.start();
45         t2.start();
46     }
47 }

    在上面的代码中创建了两个线程并分别命名为 t1, t2。调用了同一个对象 im 的两个同步方法 comeIn 和 comeInIn, 执行结果如下:

      

    在 t1 线程开始执行后,即使 t1 线程睡眠了5s,线程 t2 中的 comeInIn 方法仍然没有得到执行。这是因为 t1 线程先执行的 comeIn 方法,持有了对象 im 的锁,且 comeIn 方法并没有执行完,对象 im 的锁没有被释放,所以 comeInIn 方法无法对对象 im 加锁,就无法继续执行,只能等到 t1 线程中的 comeIn 方法执行完毕,释放对象 im 的锁,comeInIn 方法才能继续执行。

    但是如果 t1 线程调用的是对象 im 的 comeIn 方法,而 t2 线程调用的是我们声明的另外一个  ImmutableValue 对象 im2 对象的 comeInIn 方法,则这两个方法的执行是互不影响的。因为 t1 线程的 comeIn 方法要获得 im 对象的锁,而 t2 线程要获得的是 im2 对象的锁,两个锁并不是同一个锁(Java中每个实例对象都有且只有一个锁),所以这两个方法执行互不影响。

    

  二、静态方法中使用 synchronized 加锁

  静态方法中默认被加锁的对象是此静态方法所在类的 class 对象。

  

 1 class staticMethodSynchronized {
 2     public static synchronized void method1() throws InterruptedException {
 3         System.out.println(Thread.currentThread().getName() + ": start");
 4         Thread.sleep(5000);
 5         System.out.println(Thread.currentThread().getName() + ": finish");
 6     }
 7     public static synchronized void method2() throws InterruptedException {
 8         System.out.println(Thread.currentThread().getName() + ": start");
 9         Thread.sleep(5000);
10         System.out.println(Thread.currentThread().getName() + ": finish");
11     }
12 }
13 public class TestStaticClassSynchronized {
14     public static void main(String[] args) {
15         Thread t1 = new Thread(new Runnable() {
16
17             @Override
18             public void run() {
19                 // TODO Auto-generated method stub
20                 try {
21                     staticMethodSynchronized.method1();
22                 } catch (InterruptedException e) {
23                     // TODO Auto-generated catch block
24                     e.printStackTrace();
25                 }
26             }
27
28         }, "t1");
29         Thread t2 = new Thread(new Runnable() {
30
31             @Override
32             public void run() {
33                 // TODO Auto-generated method stub
34                 try {
35                     staticMethodSynchronized.method2();
36                 } catch (InterruptedException e) {
37                     // TODO Auto-generated catch block
38                     e.printStackTrace();
39                 }
40             }
41
42         }, "t2");
43         t1.start();
44         t2.start();
45     }
46 }

    在上述代码中创建了两个线程并命名为 t1,t2。 t1,t2 线程调用了 staticMethodSynchronized 类的两个静态同步方法 method1 和 method2。执行结果如下:

    

    在 t1 线程开始执行后,即使 t1 线程睡眠了5s,线程 t2 中的 method2 方法仍然没有得到执行。这是因为 t1 线程先执行的 method1 方法,持有了staticMethodSynchronized 类对象的锁,且 method1 方法并没有执行完,staticMethodSynchronized 类对象的锁没有被释放,所以 comeInIn 方法无法对staticMethodSynchronized 类对象加锁,就无法继续执行,只能等到 t1 线程中的 method1 方法执行完毕,释放 staticMethodSynchronized 类对象的锁,method2 方法才能继续执行。

  三、实例方法中使用 synchronized 关键字制造同步块

  同步块中默认被加锁的对象是此同步块括号声明中包含的对象。

  

 1 class ImmutableValue {
 2     public synchronized void comeIn() throws InterruptedException{
 3         System.out.println(Thread.currentThread().getName() + ": start");
 4         Thread.sleep(5000);
 5         System.out.println(Thread.currentThread().getName() + ": finish");
 6     }
 7     public void comeInIn() throws InterruptedException {
 8         System.out.println(Thread.currentThread().getName() + ": start");
 9         synchronized(this) {
10
11         }
12         System.out.println(Thread.currentThread().getName() + ": finish");
13     }
14 }
15 public class TestImmutableValue {
16     public static void main(String[] args) {
17         ImmutableValue im = new ImmutableValue();
18         Thread t1 = new Thread(new Runnable() {
19
20             @Override
21             public void run() {
22                 // TODO Auto-generated method stub
23                 try {
24                     im.comeIn();
25                 } catch (InterruptedException e) {
26                     // TODO Auto-generated catch block
27                     e.printStackTrace();
28                 }
29             }
30
31         }, "t1");
32         Thread t2 = new Thread(new Runnable() {
33
34             @Override
35             public void run() {
36                 // TODO Auto-generated method stub
37                 try {
38                     im.comeInIn();
39                 } catch (InterruptedException e) {
40                     // TODO Auto-generated catch block
41                     e.printStackTrace();
42                 }
43             }
44
45         }, "t2");
46         t1.start();
47         t2.start();
48     }
49 }

    由以上代码可以看到: 在 comeInIn 方法中,运用  synchronized(this) 制造同步块,要执行同步块内的代码,就必须获得 this 对象的锁(调用 comeInIn 方法的对象)。

    执行结果可能为:

    

    由此执行结果可见:t1 线程先执行了 comeIn 方法,获得了对象 im 的锁,之后由于 t1 线程进入睡眠状态,t2 线程得到运行,开始执行 comeInIn 方法,当执行到同步代码块时发现对象 im 已被加锁,无法继续执行。t1 线程睡眠结束之后继续执行,结束后释放对象 im 的锁,t2 线程才能继续执行。

  四、静态方法中使用 synchronized 关键字制造同步块

  同步块中默认被加锁的对象是此同步块括号声明中包含的对象。

  

 1 class staticMethodSynchronized {
 2     private static final Object OBJ = new Object();
 3     public static void method1() throws InterruptedException {
 4         System.out.println(Thread.currentThread().getName() + ": start");
 5         synchronized(OBJ) {
 6             System.out.println(Thread.currentThread().getName() + ": 获得锁");
 7             System.out.println(Thread.currentThread().getName() + ": 释放锁");
 8         }
 9         System.out.println(Thread.currentThread().getName() + ": finish");
10     }
11     public static void method2() throws InterruptedException {
12         System.out.println(Thread.currentThread().getName() + ": start");
13         synchronized(OBJ) {
14             System.out.println(Thread.currentThread().getName() + ": 获得锁");
15             System.out.println(Thread.currentThread().getName() + ": 释放锁");
16         }
17         System.out.println(Thread.currentThread().getName() + ": finish");
18     }
19 }
20 public class TestStaticClassSynchronized {
21     public static void main(String[] args) {
22         Thread t1 = new Thread(new Runnable() {
23
24             @Override
25             public void run() {
26                 // TODO Auto-generated method stub
27                 try {
28                     staticMethodSynchronized.method1();
29                 } catch (InterruptedException e) {
30                     // TODO Auto-generated catch block
31                     e.printStackTrace();
32                 }
33             }
34
35         }, "t1");
36         Thread t2 = new Thread(new Runnable() {
37
38             @Override
39             public void run() {
40                 // TODO Auto-generated method stub
41                 try {
42                     staticMethodSynchronized.method2();
43                 } catch (InterruptedException e) {
44                     // TODO Auto-generated catch block
45                     e.printStackTrace();
46                 }
47             }
48
49         }, "t2");
50         t1.start();
51         t2.start();
52     }
53 }

    在上述代码中,两个静态方法中的同步块都要获得对象 OBJ 的锁才能继续向下执行,执行结果可能如下:

       

    若 t1 线程先获得锁,则必须等到 t1 释放锁之后,t2 线程中同步代码块及其之后的代码才能继续执行,t2 线程先获得锁,t1 线程同理。

   总之,我认为我们只需抓住一点:Java 中每个实例对象对应一把锁且每个实例对象只有一把锁,synchronized 关键字是通过对相应的实例对象加锁来实现同步功能的(静态方法为对相应的 class 对象加锁)。在执行 synchronized 方法或 synchronized 同步块之前,我们只需判断其需要获得的对象的锁是否可获得,就可判断此方法或同步块是否可得到执行。

时间: 2024-10-29 19:05:33

Java synchronized关键字用法(清晰易懂)的相关文章

巨人大哥谈Java中的Synchronized关键字用法

巨人大哥谈Java中的Synchronized关键字用法 认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方价格synchronized基本上就搞定 了,如果说不考虑性能问题的话,这一操绝对能应对百分之九十以上的情况,若对于性能方面有要求的话就需要额外的知识比如读写锁等等.本文目的先了解透彻synchronized的基本原理. Synchronized的基本使用 Synchronized的作用主要有三个: (1)确保线程互斥的访问同步代码 

Java synchronized 关键字详解

Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 synchronized public void sync(){ } 修饰静态成员方法 synchronized public static void sync(){ } 类锁代码块 synchronized (类.class){ } 对象锁代码块 synchronized (this|对象){ } syn

Java Synchronized 关键字

本文内容 Synchronized 关键字 示例 Synchronized 方法 内部锁(Intrinsic Locks)和 Synchronization 参考资料 下载 Demo Synchronized 关键字 Java 语言提供两个基本的同步机制:synchronized 方法(synchronized methods )和 synchronized  语句(synchronized statements). 示例 先大概说一下 Java Synchronized 关键字,当它用来修饰一

Java中的Synchronized关键字用法

认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方加上synchronized修饰符基本上就搞定 了,如果说不考虑性能问题的话,这一招绝对能应对百分之九十以上的情况,若对于性能方面有要求的话就需要额外的知识比如读写锁等等.本文目的先了解透彻synchronized的基本原理. Synchronized的基本使用 Synchronized的作用主要有三个: (1)确保线程互斥的访问同步代码 (2)保证共享变量的修改能够及时可见 (3)有效解决

java synchronized关键字浅探

synchronized 是 java 多线程编程中用于使线程之间的操作串行化的关键字.这种措施类似于数据库中使用排他锁实现并发控制,但是有所不同的是,数据库中是对数据对象加锁,而 java 则是对将要执行的代码加锁. 在 java 中使用 synchronized 关键字时需要注意以下几点: 1.synchronized 是针对同一个资源的访问作出限制.这是出现该关键字的原因. 2.对于类而言,某一个线程执行到一个 synchronized 修饰的类方法或者类方法中的代码段时,该方法或者代码段

java synchronized关键字

Java中synchronized关键字和对象的内置锁结合使用,用来保护代码块在并发环境下的线程安全,可以使被保护的代码块操作原子性. synchronized关键字可以用于修饰方法来保护方法内的全部代码块,可以用synchronized(对象1) 的方式保护指定代码块.(这里说一下:很多书中都说synchronized可以给对象加锁,我实在不愿意这么说,这样让我概念混淆...因为,对象内置锁是本来就存在的,不是谁加给它的,"synchronized(对象1)"我更愿意解释成:执行到此

java synchronized关键字的底层实现

每个对象都有一个锁(Monitor,监视器锁),class对象也有锁,如果synchronized关键字修饰同步代码块,通过反编译可以看到,其实是有个monitorenter和monitorexit指令,也就是说,某个线程必须首先获得该对象的监视器锁,才能进入同步代码块,如果此时其它线程也去获取该对象的锁,则会阻塞直至当前线程释放掉监视器锁.synchronized(this)是锁当前对象,synchronized(A.class)是锁class对象. 如果synchronized关键字修饰普通

JAVA synchronized关键字锁机制(中)

synchronized 锁机制简单的用法,高效的执行效率使成为解决线程安全的首选. 下面总结其特性以及使用技巧,加深对其理解. 特性: 1. Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码.       2. 当一个线程同时访问object的一个synchronized(this)同步代码块时,其它线程仍然可以访问非修饰的方法或代码块.       3. 当多个线程同时访问object的synchronized(this)同步代码

[java] java synchronized 关键字详解

Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块.然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块. 一.synchronized同步方法 1.synchronized 同步方法,为对象锁 publ