锁升级

Java对象头

以32位虚拟机为例
普通对象:
锁升级_第1张图片
数组对象:
锁升级_第2张图片
Mark Word结构:
锁升级_第3张图片


无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁(锁升级)

在JDK1.6之前synchronized属于重量级的锁,每次加锁都是通过操作系统来申请锁,所以会造成synchronized的效率比较低,尤其是随着时代的发展,多线程高并发越来越多,synchronized效率低的缺点就越来越明显,所以JDK1.6后对它进行了优化,不再是一开始就向操作系统申请锁,锁对象分成 无锁 - 偏向锁 - 轻量级锁 - 重量级锁四个状态

在对象头的mark word中最低的三位代表锁状态,其中1位是偏向锁位两位是普通锁位,具体如下图:
锁升级_第4张图片
这次主要关注mark word的后三位的变化,根据变化我们可以得出实际上对象的锁状态可以分成无锁、偏向锁、轻量级锁、重量级锁4个状态,GC过程中有对对象的锁降级,这个不是重点,先不管了。

锁升级流程开始:
1. 无锁 - > 偏向锁:
首先最开始对象是无锁状态,当一个线程准备对这个对象加锁前验证这三个字节发现了无锁状态,把对象是否偏向设置为1,锁标志位还是01,并把markword的线程ID改为当前线程ID,此时对象处于偏向锁状态。
2. 偏向锁 -> 轻量级锁:
一个线程继续对该该对象加锁,发现是偏向锁状态,判断偏向锁线程是否是当前线程,如果是则是直接进入,如果偏向线程不是当前线程,也就是存在锁竞争,那么就撤销偏向锁,升级为轻量级锁。
3. 轻量级锁实现:
轻量级锁实现方式是各个线程在自己的线程栈生成LockRecord ,用CAS操作将锁对象的markword设置为指向自己这个线程的LockRecord的指针,设置成功者得到锁,没有成功的将继续使用CAS一直循环直到成功,所以轻量级锁也叫自旋锁
4. 轻量级锁 -> 重量级锁:
当轻量级锁自旋次数达到最大次数,就会升级为重量级锁

这里CAS操作也比较重要,具体CAS原理大家可以转载到这片文章【什么是CAS机制?】 这位博主讲的还是挺详细的


Monitor(针对于重量级锁)

Monitor被翻译为监视器管程

每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark Word中就被设置指向Monitor对象的指针。

多个线程争抢锁流程如下图
锁升级_第5张图片

Monitor结构图:
锁升级_第6张图片

  • 刚开始Monitor中Owner为nul
  • 当Thread-2执行synchronize(obj)就会将Monitor的Owner(所有者)置为Thread-2,Monitor只能有一个Owner
  • 在Thread-2上锁的过程中,如果Thread-3,Thread-4,Thread-5也来执行synchronize(obj),就会进入EntryList ,状态是BLOCKED
  • Thread-2执行完同步代码块的内容,然后唤醒EntryList中等待的线程来竞争锁,竞争时是非公平的(并非是谁先来是获得锁,这里获得锁是随机的
  • 图中WaitSet中的Thread-0,Thread-1是之前获得过锁,但条件不满足(被调用了wait方法),然后进入WAITING状态的线程

注意:

  • synchronize必须是进入同一个对象的monitor才有上述的效果
  • 不加synchronize的对象不会关联监视器,不遵从以上规则

你可能感兴趣的:(多线程,并发,java,多线程)