java中每个对象都可作为锁,锁有四种级别,按照量级从轻到重分为:无锁、偏向锁、轻量级锁、重量级锁。每个对象一开始都是无锁的,随着线程间争夺锁,越激烈,锁的级别越高,并且锁只能升级不能降级。
一、java对象头
锁的实现机制与java对象头息息相关,锁的所有信息,都记录在java的对象头中。用2字(32位JVM中1字=32bit=4baye)存储对象头,如果是数组类型使用3字存储(还需存储数组长度)。对象头中记录了hash值、GC年龄、锁的状态、线程拥有者、类元数据的指针。
二、偏向锁
在实际应用运行过程中发现,“锁总是同一个线程持有,很少发生竞争”,也就是说锁总是被第一个占用他的线程拥有,这个线程就是锁的偏向线程。
那么只需要在锁第一次被拥有的时候,记录下偏向线程ID。这样偏向线程就一直持有着锁,直到竞争发生才释放锁。以后每次同步,检查锁的偏向线程ID与当前线程ID是否一致,如果一致直接进入同步,退出同步也,无需每次加锁解锁都去CAS更新对象头,如果不一致意味着发生了竞争,锁已经不是总是偏向于同一个线程了,这时候需要锁膨胀为轻量级锁,才能保证线程间公平竞争锁。
1.加锁
偏向锁加锁发生在偏向线程第一次进入同步块时,CAS原子操作尝试更新对象的Mark Word(偏向锁标志位为"1",记录偏向线程的ID)。
2.撤销偏向锁
当有另一个线程来竞争锁的时候,就不能再使用偏向锁了,要膨胀为轻量级锁。
竞争线程尝试CAS更新对象头失败,会等待到全局安全点(此时不会执行任何代码)撤销偏向锁。
三、轻量级锁
轻量锁与偏向锁不同的是:
- 轻量级锁每次退出同步块都需要释放锁,而偏向锁是在竞争发生时才释放锁
- 每次进入退出同步块都需要CAS更新对象头
- 争夺轻量级锁失败时,自旋尝试抢占锁
可以看到轻量锁适合在竞争情况下使用,其自旋锁可以保证响应速度快,但自旋操作会占用CPU,所以一些计算时间长的操作不适合使用轻量级锁。
1.加锁
加锁过程和偏向锁加锁差不多,也是CAS修改对象头,只是修改的内容不同。
- 在MarkWord中保存当前线程的指针
- 修改锁标识位为“00”
采用CAS操作的原因是,不想在加锁解锁上再加同步
如果对象处于无锁状态(偏向锁标志位为"0",锁标志位为"01"),会在线程的栈中开辟个锁记录空间(Lock Record),将Mark Word拷贝一份到Lock Record中,称为Displaced Mark Word,在Lock Record中保存对象头的指针(owner)。
接下来CAS更新MarkWord,将MarkWord指向当前线程,owner指向MarkWord,如果失败了,则意味着出现了另一个线程竞争锁,此时需要锁膨胀为轻量级锁。
2.解锁
用CAS操作锁置为无锁状态(偏向锁位为"0",锁标识位为"01"),若CAS操作失败则是出现了竞争,锁已膨胀为重量级锁了,此时需要释放锁(持有重量级锁线程的指针位为"0",锁标识位为"10")并唤醒重量锁的线程。
3.膨胀为重量级锁
当竞争线程尝试占用轻量级锁失败多次之后,轻量级锁就会膨胀为重量级锁,重量级线程指针指向竞争线程,竞争线程也会阻塞,等待轻量级线程释放锁后唤醒他。
三、重量级锁
重量级锁的加锁、解锁过程和轻量级锁差不多,区别是:竞争失败后,线程阻塞,释放锁后,唤醒阻塞的线程,不使用自旋锁,不会那么消耗CPU,所以重量级锁适合用在同步块执行时间长的情况下。
四、参考
- 《Java并发编程的艺术》
- 《轻量级锁与偏向锁》
- 《Synchronized下的三种锁:偏向锁 轻量锁 重量锁 理解》
- 《JAVA锁的膨胀过程和优化》
相关推荐
当线程开始尝试获取锁时,Java会引入三种不同类型的锁:偏向锁、轻量级锁和重量级锁。 1. **偏向锁**:偏向锁是默认的锁状态,假设只有一个线程访问同步代码块,它会尝试将Mark Word中的线程ID设为当前线程ID,这样...
理解并熟练运用偏向锁、轻量级锁和重量级锁的原理,有助于编写出更加高效且线程安全的并发代码。 最后,对于源码阅读爱好者来说,深入研究JVM源码中的锁实现细节,如`ObjectMonitor`类,可以进一步提升对并发编程的...
很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了Java SE1.6中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁,...
2. 锁的分类:synchronized 锁可以分为轻量级锁、偏向锁和重量级锁三种。 3. 轻量级锁:轻量级锁是 synchronized 锁的一种实现方式,使用 CAS 操作来更新对象的 Mark Word。轻量级锁的加锁过程可以分为三步:创建锁...
5. 偏向锁(Bias Locking):在Java的锁实现中,偏向锁是为了优化轻量级锁的一种方式。首次获取锁的线程会标记为“偏向”,后续该线程再次请求时,无需进行锁竞争,提高性能。 6. 轻量级锁(Lightweight Locking)...
- **重量级锁**:当轻量级锁争用失败时,将会升级为重量级锁,这会导致线程挂起和唤醒操作。 #### 三、自定义锁实现同步 除了使用 `synchronized` 关键字外,我们还可以自己实现锁来实现同步。下面将通过一个简单...
锁升级可以分为四个阶段:无锁、偏向锁、轻量级锁和重量级锁。 4.1、无锁 无锁是指没有锁的状态。 4.2、偏向锁 偏向锁是指 Java 虚拟机在运行时对锁的偏向状态。 4.3、偏向锁流程 偏向锁流程是指 Java 虚拟机...
- **重量级锁:** 当轻量级锁不足以解决问题时,JVM 将升级到重量级锁,这涉及到内核态的转换。重量级锁是最慢但最可靠的锁实现。 这些优化策略提高了 `Synchronized` 的效率,使其成为更灵活、更高效的同步工具。...
7. **偏向锁/轻量级锁/重量级锁** - **偏向锁**假定一个线程连续获取锁,就不再进行加锁操作,仅在多线程争抢时升级为轻量级锁。 - **轻量级锁**利用CAS操作,比重量级锁更高效,但如果锁存在竞争,会升级为重量级...
Java中的锁机制主要分为三种:偏向锁、轻量级锁和重量级锁。 偏向锁是Java锁机制的一种,用于解决线程之间的竞争问题。偏向锁可以重入和经常使用某一个线程,且不会发生竞争。偏向锁的结构由 hashcode、age、biased...
锁的状态从低到高依次为无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁,升级的过程就是从低到高,降级在一定条件也是有可能发生的。 四、锁的种类 1. 自旋锁:由于大部分时候,锁被占用的时间很短,共享变量的锁定时间...
Java虚拟机在某些情况下会自动进行锁升级,即从偏向锁升级到轻量级锁,再升级到重量级锁。这种机制旨在减少锁的竞争,提高程序的并发性能。 ##### 2. 死锁避免 为了避免死锁的发生,Java提供了一些工具和技术,如`...
- **轻量级锁**:当多个线程竞争同一锁时,偏向锁会升级为轻量级锁。轻量级锁通过自旋的方式等待锁的释放。 - **重量级锁**:当自旋等待时间过长或线程太多时,轻量级锁会升级为重量级锁,使用操作系统互斥量来...
当对象被synchronized锁定时,MarkWord会记录锁的相关信息,如轻量级锁或重量级锁的状态。 2. Klass Pointer:这部分存储的是对象所属类的元数据的指针,即对象的类类型。通过这个指针,虚拟机能够识别对象属于哪个...
总结来说,`synchronized`锁的膨胀过程是从无锁到可偏向的无锁,再到轻量级锁,最后到重量级锁,这个过程中涉及到了Java对象头Mark Word的变更以及JVM的优化策略。理解这个过程有助于我们在设计多线程代码时选择合适...
- **锁升级与锁粗化**:为了提高效率,Java虚拟机会根据情况优化锁的实现,包括从偏向锁到轻量级锁再到重量级锁的升级,以及在多个连续的同步代码块之间进行锁粗化。 5. **synchronized的局限性和替代方案** - **...
- **重量级锁**:当轻量级锁竞争失败时,就会升级为重量级锁,此时会真正地利用操作系统的互斥锁机制。 - **非公平锁**: - Synchronized默认是非公平锁。这意味着即便线程已经在等待队列中排队,当锁被释放时,...
在JDK 6及以后版本,JVM引入了偏向锁、轻量级锁和重量级锁的概念,这三种锁对应不同的竞争情况,JVM会根据实际情况自动切换锁的类型。偏向锁是单线程自始至终只由一个线程来访问同步块的优化方式;轻量级锁使用CAS...
讨论了监视器锁的加锁过程、锁的状态(偏向锁、轻量级锁、重量级锁)以及锁的膨胀升级过程。此外,文章还覆盖了锁优化技术,例如锁消除和逃逸分析,以及这些技术对Java性能的影响。通过对synchronized关键字的深入...