Java支持同步机制的是Monitor
。Monitor就像是拥有一个特殊房间的建筑,在同一时间里,这间特殊的房间只能被一个线程拥有。html
Monitor支持两种同步机制:java
wait-notify又能够称做’Singal-continue’。当线程得到 notify,这就是一个信号,线程开始拥有 monitor的全部权,可以 继续 执行 monitor region。执行完以后,此线程释放monitor,一个等待的线程则会得到同样的机会
Monitor的模型以下:安全
1 表示线程刚到达 monitor region ,即 enter the monitor
2 表示线程获取 monitor的全部权,即acquiring the monitor
3 表示线程执行了 wait,交出全部权,即releasing the monitor
4 表示原来拥有 monitor 的线程执行了 notify ,刚好被这个线程获取全部权
5 表示线程执行完了 monitor region,即exiting the monitor
多线程
Monitor特地把等待的线程分红了两个部分,Entry Set和Wait Set,Entry Set表示线程刚执行到 Monitor region,而Wait Set则是因为线程执行了wait方法而进入的区域。注意到Object的 notify 以及 notifyAll 要唤醒的对象就处于 Wait Set,换句话说,若是退出 monitor 的线程没有执行 notify/notifyAll ,那么只有 Entry Set 可以获取执行的权限 。若是执行了,则Entry Set和Wait Set中全部的线程都会竞争谁最终可以获取 monitor 的能力一个线程要离开Wait Set,要么是原拥有 monitor 的线程执行了 notify/notifyAll,要么是wait的时间到了,JVM 会触发一个notifyjvm
Java可以共享的数据包括两部分:ide
对于局部变量,他们存储在栈中,属于线程私有,不会存在共享一说。
单个线程能够同时锁住一个对象屡次,JVM会记住锁住的总次数,每一次释放锁,总次数减一,只有在这个次数变成0的时候,这个锁才有可能被其它线程持有ui
JVM使用的指令为this
public class SynchronizedTest { private int i=0; public void syn(){ synchronized (this){ i++; } } }
javap -c SynchronizedTest.class
执行后对应的指令以下spa
public class main.lockTest.SynchronizedTest { public main.lockTest.SynchronizedTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: iconst_0 6: putfield #2 // Field i:I 9: return public void syn(); Code: 0: aload_0 // aload_0 属于 aload_<n> 系列指令的一种。表示获取一个本地变量的引用,而后放入栈中 1: dup //弹出栈顶的单字节,而后入栈两次,至关于拷贝了栈顶元素 2: astore_1 // astore_<n>系列指令的一种。从栈顶获取对象的引用,并存入本地变量 3: monitorenter //获取引用对象的锁 4: aload_0 5: dup 6: getfield #2 // Field i:I 从栈中获取对象的引用,而后获得它的值 9: iconst_1 // iconst_<n> 的一种,将常量放入栈中 10: iadd // 从操做栈中弹出两个integer,把他们相加,而后将结果从新存入栈中 11: putfield #2 // Field i:I 将值存入引用对象 14: aload_1 15: monitorexit // 释放引用对象的锁 16: goto 24 // 跳转到下一个指令的位置 19: astore_2 20: aload_1 21: monitorexit 22: aload_2 23: athrow //从操做栈中删掉对象的引用,并抛出这个对象的异常 24: return //执行返回 Exception table: from to target type 4 16 19 any 19 22 19 any }
注意到,若是抛出了异常,也会执行 monitorexit
。印证了不管如何,只要离开了monitor region,锁都会被释放线程
public class SynchronizedTest { private int i=0; public synchronized void syn(int i){ i++; } }
对应指令以下
public class main.lockTest.SynchronizedTest { public main.lockTest.SynchronizedTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: iconst_0 6: putfield #2 // Field i:I 9: return public synchronized void syn(int); Code: 0: iinc 1, 1 3: return }
能够看到两个区别