synchronized是一个java的关键字,是java语言为了解决并发编程中存在的原子性、可见性和有序性的问题,提供了一系列跟并发处理有关的关键字,我们今天要来简单了解一下synchronized。
package com.zero.day3; /** * @Description: synchronized * @Author: Zero * @Date: 2019/12/10 */ public class SynchronizedDemo1 { // 同步方法 public synchronized void wc1 () { System.out.println("我在上厕所1"); } // 同步方法 (静态) public static void wc2 () { synchronized (SynchronizedDemo1.class) { System.out.println("我在上厕所2"); } } // 同步代码块 public void wc3 () { synchronized (this) { System.out.println("我在上厕所3"); } } } 复制代码
上面三个简单的方法中都添加了 普通同步方法时:锁是当前实例对象synchronized关键字,也就是在同一时间,每个方法只能被单个线程访问,一个厕所同一时间只有有一个人在用。 静态同步方法时:锁是当前类的class对象(因为静态方法在对象之前运行,运行静态方法的时候可能都没有对象,所以是当前类的class对象) 同步方法块:锁是括号里面的对象
我们现在对上面的方法进行反编译操作
LINENUMBER 8 L0 ALOAD 0 INVOKESPECIAL java/lang/Object.<init> ()V RETURN L1 LOCALVARIABLE this Lcom/zero/day3/SynchronizedDemo1; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x21 public synchronized wc1()V L0 LINENUMBER 15 L0 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "/u6211/u5728/u4e0a/u5395/u62401" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V L1 LINENUMBER 16 L1 RETURN L2 LOCALVARIABLE this Lcom/zero/day3/SynchronizedDemo1; L0 L2 0 MAXSTACK = 2 MAXLOCALS = 1 // access flags 0x9 public static wc2()V TRYCATCHBLOCK L0 L1 L2 null TRYCATCHBLOCK L2 L3 L2 null L4 LINENUMBER 21 L4 LDC Lcom/zero/day3/SynchronizedDemo1;.class DUP ASTORE 0 MONITORENTER L0 LINENUMBER 22 L0 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "/u6211/u5728/u4e0a/u5395/u62402" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V L5 LINENUMBER 23 L5 ALOAD 0 MONITOREXIT L1 GOTO L6 L2 FRAME FULL [java/lang/Object] [java/lang/Throwable] ASTORE 1 ALOAD 0 MONITOREXIT L3 ALOAD 1 ATHROW L6 LINENUMBER 24 L6 FRAME CHOP 1 RETURN MAXSTACK = 2 MAXLOCALS = 2 // access flags 0x1 public wc3()V TRYCATCHBLOCK L0 L1 L2 null TRYCATCHBLOCK L2 L3 L2 null L4 LINENUMBER 29 L4 ALOAD 0 DUP ASTORE 1 MONITORENTER L0 LINENUMBER 30 L0 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "/u6211/u5728/u4e0a/u5395/u62403" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V L5 LINENUMBER 31 L5 ALOAD 1 MONITOREXIT L1 GOTO L6 L2 FRAME FULL [com/zero/day3/SynchronizedDemo1 java/lang/Object] [java/lang/Throwable] ASTORE 2 ALOAD 1 MONITOREXIT L3 ALOAD 2 ATHROW L6 LINENUMBER 32 L6 FRAME CHOP 1 RETURN L7 LOCALVARIABLE this Lcom/zero/day3/SynchronizedDemo1; L4 L7 0 MAXSTACK = 2 MAXLOCALS = 3 } 复制代码
我们仔细找找其实可以找到MONITORENTER跟MONITOREXIT这两个单词,接下来,我就用比较简单粗暴的语言来给大家随便说说这个过程。 假如这个时候呢有三个线程Thread1,Thread2, Thread3都同时来调用一个方法,那么代码肯定是共享的啦,那么当这个方法function没有加锁的时候,Thread1来执行这个代码,执行到一半Thread2也可以来执行,Thread3当然也可以执行。当这个方法function加了锁之后就不一样了,这代码编译就会产生这两个指令,当Thread1来抢到CPU的执行权之后就来执行这个方法了啊,碰到这个MONITORENTER的时候,这就厉害了啊!其他的线程都给调用了wait方法,大家都知道当线程调用了wait方法之后,就会进入等待状态,谁都救不了它们,这个时候Thread1就自己大摇大摆地执行完了这个加锁的方法,自然就有了MONITOREXIT指令,这个时候线程还在等待?怎么办,当线程处于wait的时候我们都知道会调用notifyAll方法去唤醒所有的其他线程,这个时候所有的线程就苏醒了继续执行。
小编是一枚Java Coder,业余写文章,现主营微信公众号《Java患者》,喜欢的话关注我的公众号或者加我微信我们一起学习Java