JVM 锁优化:Java 原生锁的背后!
1. 前言
在多线程编程中,锁是一个非常重要的话题。Java 原生提供了 synchronized 关键字和 Lock 接口等方式来实现锁。而 JVM 在处理锁时,也做了不少优化。本文将阐述 JVM 对 Java 的原生锁做了哪些优化。
2. 摘要
本文首先简单介绍了 Java 中锁的两种实现方式:synchronized 和 Lock 接口。然后分别从 JVM 级别进行解析:synchronized 的优化主要包括:偏向锁、轻量级锁和重量级锁等;而 Lock 接口的优化主要包括:公平锁和非公平锁等。本文最后给出了相应的代码示例和测试用例,最终得出结论:JVM 对 Java 的原生锁做了很多优化,这些优化大大提升了锁的性能和效率。
3. 正文
3.1 Java 中锁的实现方式
在 Java 中,锁主要有两种实现方式:synchronized 和 Lock 接口。
3.1.1 synchronized
synchronized 关键字是 Java 中最基本的锁实现方式。它是在 JVM 层面实现的,具有自动释放锁、重入锁和可见性等特性,使用简单方便。
3.1.2 Lock 接口
Lock 是 JDK 提供的高级锁机制,它的实现方式是基于 Java 中的 AQS(AbstractQueuedSynchronizer)类实现的。AQS 是一个同步框架,它可以用于构建同步器,其中包括 ReentrantLock 和 ReentrantReadWriteLock 等。
3.2 synchronized 的优化
JVM 对 synchronized 锁进行了很多优化,主要包括以下三种:
3.2.1 偏向锁
偏向锁:这种优化是 JVM 为了减少同步无竞争情况下的性能消耗而引入的。当一个线程访问同步块并获取锁时,JVM 会在对象头和线程栈上做一个记录,记录下线程 ID、对象头指针和锁标志。当这个线程持有锁的时间超过一定阈值时,JVM 会将锁升级为轻量级锁;当线程竞争锁时,锁会直接升级为重量级锁。
3.2.2 轻量级锁
轻量级锁:这种优化是为了在低竞争条件下,减少锁的开销而引入的。当一个线程请求锁时,JVM 会优先使用 CAS(Compare And Swap)操作将对象头指针指向线程栈上的锁记录,如果 CAS 操作成功,则表示该线程获取到了锁,并且锁的状态改变为轻量级锁状态;如果 CAS 操作失败,则表示有其他线程竞争此锁,线程会进入自旋,不需要系统调用,因此效率极高。
3.2.3 重量级锁
重量级锁:这种优化是为了在高竞争条件下,保证线程竞争公平而引入的。如果一个线程尝试获取锁时,发现锁已经被其他线程持有,它会陷入阻塞状态,直到锁被释放。
3.3 Lock 接口的优化
Lock 接口相比于 synchronized 关键字,优化点更多,主要包括以下两种:
3.3.1 公平锁
公平锁:在多个线程竞争同一个锁时,如果锁是公平锁,则每个线程都会按照它们发出请求的时间顺序来获取锁,这种情况下线程获取锁的顺序是有序的。
3.3.2 非公平锁
非公平锁:在多个线程竞争同一个锁时,如果锁是非公平锁,则不保证线程获取锁的顺序,这样可能会导致某些线程一直无法获取到锁。
3.4 代码示例和测试用例
下面给出了对于 synchronized 和 Lock 接口的相应代码示例和测试用例:
3.4.1 synchronized 实现的锁机制
示例代码如下:
测试用例说明:创建一个 SyncJava 实例,实现了 increment()方法和 decrement()方法,其中使用了 synchronized 关键字保证线程安全。创建一个线程池,启动 1000 个线程,每个线程执行一次 increment()方法和一次 decrement()方法。最终输出 count 的值,究竟该 count 值会是多少呢?咱们拭目以待。
实际运行截图如下:
由于 synchronized 关键字保证了线程安全,最终 count 值只会跟初始值一样,为 0,实际上输出结果也跟预期结果是一致的。
3.4.2 Lock 接口实现的锁机制
示例代码如下:
测试用例说明:创建一个 LockTest 实例,实现了 increment()方法和 decrement()方法,其中使用了 Lock 接口来实现线程安全。与上述测试保持一致,也是创建一个线程池,启动 1000 个线程,每个线程执行一次 increment()方法和一次 decrement()方法,最终测试输出 count 的值。
实际运行截图如下:
很明显,结果为 0,这就验证了多线程中安全执行 increment()和 decrement()方法,每个线程都会按照它们发出请求的时间顺序来获取锁,哪怕执行一千次一万次,count 值也是顺序一加一减,最后 count 值只能为 0.
4. 结论
总的来说,JVM 对 Java 的原生锁进行了很多优化,主要包括偏向锁、轻量级锁、重量级锁、公平锁和非公平锁等。这些优化大大提升了锁的性能和效率。在实际编程中,我们需要了解 Java 中不同的锁实现方式,并根据实际场景选择最适合的锁。
最后
大家如果觉得看了本文有帮助的话,麻烦给个三连(点赞、分享、转发)支持一下哈。
评论