Synchronized底层实现原理
synchronized介绍:
synchronized 关键字在多线程环境下作为线程安全的同步锁
synchronized作用:
1.同步代码块(当前对象锁[this] 或 自定义对象锁) 2.同步静态方法(当前类的Class实例,Class数据存在永久代中,该类全局锁) 3.同步非静态方法(当前对象锁)
同步代码块:
//Java代码 public void syncronizedTest(){ synchronized (this){ System.out.println("hello world"); } } //代码反汇编
JVM使用monitorenter和monitorexit两个指令实现同步,即JVM为代码块的前后真正生成了两个字节码指令来实现同步功能。
monitorenter/monitorexit: 每个对象都会与一个monitor(监视器锁)相关联,当某个monitor被拥有后就会被锁住,当线程执行到monitorenter指令时,就会去尝试获得对应的monitor 1.每个monitor维护一个记录拥有次数的计数器,未被拥有monitor的该计数器为0,当一个线程获得monitor(执行monitorenter)后,该计数器自增变为1 2.当同一个线程再次获得该monitor的时候,计数器再次自增 3.当不同线程想要获得该monitor的时候,就会被阻塞 4.当同一个线程释放monitor(执行monitorexit指令)时,计数器自减。当计数器减为0时,monitor将被释放,其他线程可获得该monitor
同步方法(静态方法,非静态方法):
//静态方法 public static synchronized void syncronizedStaticTest(){ System.out.println("hello world"); } //非静态方法 public synchronized void syncronizedTest(){ System.out.println("hello world"); } //静态方法与非静态方法反汇编
JVM使用acc_synchronized标识来实现,即JVM通过在方法访问标识符(flags)中加入acc_synchronized来实现同步功能
同步方法是隐式的,一个同步方法会在运行时常量池中的method_info结构体中存放acc_synchronized标识符。 当一个线程访问方法时,会去检查是否存在acc_synchronized标识符,如果存在,则要先获得对应的monitor锁,然后执行方法,当方法执行结束(正常return或抛出异常)都会释放对应的monitor锁。如果此时有其他线程也想要访问这个方法时,会因得不到monitor锁而阻塞。
总结:
同步方法和同步代码块底层都是通过monitor来实现同步的。 同步方法和同步代码块的区别: 同步方法是通过方法中的access_flags中设置acc_synchronized标志来实现,同步代码块是通过monitorenter和monitorexit来实现。每个对象都与monitor相关联,而monitor可以被线程拥有或释放。