synchronized锁什么?
锁对象,可能包括:this, 临界资源对象,class类对象
锁的底层实现
同步代码块基于monitor enter和monitor exit指令实现同步,
同步方法基于读取运行时常量池中方法的ACC_SYNCHRONIZED标志来隐式实现。
对象内存的组成
对象头:存储对象的hashcode锁信息GC信息类型指针
实例变量
填充数据:虚拟机要求对象的起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅为了字节对齐。
执行过程
当执行synchronized同步方法或同步代码块时,会在对象头中记录锁标记,锁标记指向monitor对象的起始地址。
monotor对象:每个对象都存在一个monitor与之关联,monitor可以与对象一起创建销毁或当线程试图获取对象锁时自动生成。当monitor对象被某个线程持有后,便处于锁定状态
monitor是由ObjectMonotor实现的。ObjectMonitor中包括:_owner标记,两个队列,_waitSet\_entryList
所线程并发访问同一个同步代码时,首先进入_entryList, 当线程获取锁标记后,_owner记录此线程,且在monitor中的计数器执行+1操作代表锁定。其他线程在_entryList中继续阻塞。
如果执行线程调用wait方法,则monitor中的计数器置为0,_owner置为null,代表放弃锁,执行线程进入waitset中阻塞。
如果执行线程调用notify otifyAll,_waitset中的线程被唤醒,进入_entryList中阻塞,等待获取锁标记。
如果执行线程的同步代码执行结束,会释放锁标记,monitor中的计数器置为0,_owner置为null
在jdk1.6之前,synchronized使用的是重量锁。由于重量锁引起的线程阻塞唤醒开销太大,于是对此做了优化。
先提供偏向锁,如果不满足的时候,升级为轻量级锁,再不满足,升级为重量级锁。
锁只能升级,不能降级。
偏向锁 : 它会偏向第一个访问锁的线程,如果不存在多线程竞争,是不需要触发同步的,这种情况下就会给线程加一个偏向锁。如果存在其他线程竞争,那么持有偏向锁的线程会被挂起,锁升级为轻量级锁。
它通过消除资源无竞争情况下的同步原语,进一步提高了程序的性能。
轻量级锁:先不把线程阻塞挂起前,先让线程空循环等待。轻量级锁适用于同步代码执行很快的场景,这样线程原地等待很短时间就能够获得锁了,而不需阻塞唤醒线程。