本文共 1209 字,大约阅读时间需要 4 分钟。
synchronized代码块:
首先我们先建立一个synchronized同步语句块:
public class SynchronizedTest { public void method() { synchronized(this) { System.out.println("synchronized");
然后对其进行反编译:
每个对象有一个监视器锁(monitor),当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:
执行monitorexit的线程必须是共享变量所对应的monitor的所有者,指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者,其他被阻塞的线程可以尝试去获取这个monitor的所有权
我们可以看到,在执行synchronized同步代码块时,在最后会有两个monitorexit,这个主要是防止在同步代码块中线程因异常退出,而锁没有得到释放,这必然会造成死锁(等待的线程永远获取不到锁)。因此最后一个monitorexit是保证在异常情况下,锁也可以得到释放,避免死锁synchronized方法:
public class SynchronizedMethod { public synchronized void method2(){ System.out.println("Synchronized2"); }}对于synchronized方法而言,javac为其生成了一个ACC_SYNCHRONIZED关键字,在JVM进行方法调用时,发现调用的方法被ACC_SYNCHRONIZED修饰,则会先尝试获得锁
很多synchronized里面的代码只是一些很简单的代码,执行时间非常快,此时等待的线程都加锁可能不是一种合适的操作,因为线程阻塞设计到用户态和内核态切换的问题,既然synchronized里面的代码执行得非常快,那么可以让等待锁的线程不要被阻塞,而是在synchronized的边界做忙循环,这就是自选
锁的状态总共有四种:无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级到重量级锁(锁的升级是单项的,也就是说只能从低到高升级,不会出现锁的降级)
转载地址:http://nhjmb.baihongyu.com/