synchronized是由一对monitorenter和monitorexit指令来实现同步的,在JDK6之前,monitor的实现是依靠操作系统内部的互斥锁来实现的,所以需要进行用户态和内核态的切换,所以此时的同步操作是一个重量级的操作,性能很低。
但是,JDK6带来了新的变化,提供了三种monitor的实现方式,分别是偏向锁,轻量级锁和重量级锁,即锁会先从偏向锁再根据情况逐步升级到轻量级锁和重量级锁。
这就是锁升级
在锁对象的对象头里面有一个threadid字段,默认情况下为空,当第一次有线程访问时,则将该threadid设置为当前的线程id,我们称为让其获取偏向锁,当线程执行结束,则重新将threadid设置为空。
之后,如果线程再次进入的时候,会先判断threadid与该线程的id是否一致,如果一致,则可以获取该对象,如果不一致,则发生锁升级,从偏向锁升级为轻量级锁
轻量级锁的工作模式是通过自旋循环的方式来获取锁,看对方线程是否已经释放了锁,如果执行一定次数之后,还是没有获取到锁,则发生锁升级,从轻量级锁升级为重量级锁。
使用锁升级的目的是为了减少锁带来的性能消耗。
通过反编译查看字节码,就可以看到相关的指令
javap -verbose Test.class
源码:就是写了synchronized同步代码块控制线程安全
1 | Code: |
synchronized如何保证可见性的?
首先,我们需要知道可见性原理
两个线程如何保证变量信息的共享可见性?需要经历以下的流程
线程A-》本地内存A(共享变量副本)-》主内存(共享变量)
如果有变更,需要将本地内存的变量写到主内存,对方才可以获取到更新。
这个是提前知识。
那么,synchronized是如何保证可见性的
就是当获取到锁之后,每次读取都是从主内存读取,当释放锁的时候,都会将本地内存的信息写到主内存,从而实现可见性