脚本宝典收集整理的这篇文章主要介绍了synchronized、ReentrantLock、volatile,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活; ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。
synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁; ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。
synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以响应中断。
ReentrantLock可以实现公平锁机制,synchronized不行。
对象是放在堆内存中的,对象大致可以分为三个部分,分别是对象头,实例变量和填充字节。
假如有如下的类,a=100这个信息就存储在实例变量中
public class test {
int a = 100;
}
填充数据主要是为了方便内存管理,如你想要10字节的内存,但是会给你分配16字节的内存,多出来的字节就是填充数据
synchronized不论是修饰方法还是代码块,都是通过持有修饰对象的锁来实现同步,那么synchronized锁对象是存在哪里的呢?答案是存在锁对象的对象头Mark Word,来看一下Mark Word存储了哪些内容?
由于对象头的信息是与对象自身定义的数据没有关系的额外存储成本,因此考虑到JVM的空间效率,Mark Word 被设计成为一个非固定的数据结构,以便存储更多有效的数据,它会根据对象本身的状态复用自己的存储空间,也就是说,Mark Word会随着程序的运行发生变化,变化状态如下 (32位虚拟机):
在JDK1.6之前,synchronized都是重量级锁,1.6版本之后,进行了锁的升级;锁可以升级但不能降级,但是偏向锁状态可以被重置为无锁状态。
无锁 没有线程运行时,此时处于无锁状态。
偏向锁 当线程1访问代码块并获取锁对象时,会在java对象头和栈帧中记录偏向的锁的threadID,因为偏向锁不会主动释放锁,因此以后线程1再次获取锁的时候,需要比较当前线程的threadID和Java对象头中的threadID是否一致,如果一致(还是线程1获取锁对象),则无需使用CAS来加锁、解锁;如果不一致(其他线程,如线程2要竞争锁对象,而偏向锁不会主动释放因此还是存储的线程1的threadID),那么需要查看Java对象头中记录的线程1是否存活,如果没有存活,那么锁对象被重置为无锁状态,其它线程(线程2)可以竞争将其设置为偏向锁;如果存活,那么立刻查找该线程(线程1)的栈帧信息,如果还是需要继续持有这个锁对象,那么暂停当前线程1,撤销偏向锁,升级为轻量级锁,如果线程1 不再使用该锁对象,那么将锁对象状态设为无锁状态,重新偏向新的线程。
自旋锁(轻量级锁)
重量级锁 https://blog.csdn.net/zzti_erlie/article/details/103997713
以上是脚本宝典为你收集整理的synchronized、ReentrantLock、volatile全部内容,希望文章能够帮你解决synchronized、ReentrantLock、volatile所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。