学习锁机制之前首先要知道对象头是什么:对数组对象和非数组对象分别用3或2字的长度记录对象的一些信息
其中mark word就是和锁有关的头,第二个是指向方法区中该对象的类型数据指针,第三个是数组对象特有的头,放的数组长度(这也是为什么数组的length不是成员变量的原因,仅仅是编译器现象)
mark word根据不同的状态是会放不同信息的:
java1.6之后加入了偏向锁和轻量级锁,所以一共有四种锁状态:无锁,偏向,轻量级,重量级,随着竞争加大锁状态会升级。锁只能升级不能降级,为的是增加获得锁和释放锁的效率。
偏向锁
适用场景:只有一个或大多数时间只有一个线程使用该锁(无竞争或竞争小)
进
入同步代码前,当锁对象是无锁状态被第一次获得,使用cas把锁对象mark
word中的线程id指向自己,并一直持有锁对象。以后再进入同步代码中只需要判断该锁对象是否指向当前线程,如果是的话因为一直没有释放锁对象,也不用
获得锁,因此提升了效率。如果不是则判断锁对象指向的线程是否活着,如果死了则把锁对象重新指向当前线程,如果活着使用cas竞争锁,进入轻量级锁的场景
(也叫作偏向锁的撤销,没有偏向锁的解锁一说)。
偏向锁在java1.6之后默认开启,但是会在应用程序启动几秒之后才激活,因此可以使用jvm参数来优化。
当确定任务中有多个线程使用一把锁,并且竞争频繁的时候可以关闭偏向锁默认进入轻量级锁-XX:UseBiasedLocking=false。-XX:BiasedLockingStartupDelay=0关闭延迟。
轻量级锁
适用场景:多个线程使用同一把锁,但是大部分时间都是一个线程使用()。
执
行同步代码之前会在栈中创建用于存取锁记录的空间,把锁对象的mark word复制过来,尝试使用cas将mark
word替换为指向锁记录的指针。如果成功获得锁,如果失败通过自旋尝试获得锁,还失败则进入重量级锁场景并阻塞。当轻量级锁解锁的时候,会尝试把线程栈
中锁记录空间的内容恢复给锁对象mark word,如果成功表示没有竞争,如果失败表示有竞争唤醒阻塞的线程然后进入重量级锁的竞争。
重量级锁对象会指向运行jvm的操作系统提供的互斥量。
阅读(1784) | 评论(0) | 转发(0) |