StampedLock 是 Java 8 引入的一种高级的锁机制,它位于 java.util.concurrent.locks 包中。与传统的读写锁(ReentrantReadWriteLock)相比,StampedLock 提供了更灵活和更高性能的锁解决方案,尤其适用于读操作远多于写操作的场景。
相比于 Java 中的其他锁,StampedLock 具有以下特点:
StampedLock 有三种读写方法:
其中 readLock() 和 writeLock() 方法与 ReentrantReadWriteLock 的用法类似,而 tryOptimisticRead() 方法则是 StampedLock 引入的新方法,它用于非常短的读操作。
因此,我们在加锁时,可以使用性能更高的读乐观锁来替代传统的读锁,如果能加锁成功,则它可以和其他线程(即使是写操作)一起执行,也无需排队运行(传统读锁遇到写锁时需要排队执行),这样的话 StampedLock 的执行效率就会更高,它是使用如下:
// 创建 StampedLock 实例StampedLock lock = new StampedLock();// 获取乐观读锁long stamp = lock.tryOptimisticRead(); // 读取共享变量if (!lock.validate(stamp)) { // 检查乐观读锁是否有效 stamp = lock.readLock(); // 如果乐观读锁无效,则获取悲观读锁 try { // 重新读取共享变量 } finally { lock.unlockRead(stamp); // 释放悲观读锁 }}// 获取悲观读锁long stamp = lock.readLock(); try { // 读取共享变量} finally { lock.unlockRead(stamp); // 释放悲观读锁}// 获取写锁long stamp = lock.writeLock(); try { // 写入共享变量} finally { lock.unlockWrite(stamp); // 释放写锁}
使用乐观读锁的特性可以提高读操作的并发性能,适用于读多写少的场景。如果乐观读锁获取后,在读取共享变量前发生了写入操作,则 validate 方法会返回 false,此时需要转换为悲观读锁或写锁重新访问共享变量。
在使用 StampedLock 时,需要注意以下几个问题:
以下代码中线程 2 会导致 CPU 100% 的问题,如下代码所示:
public void runningTask() throws Exception{ final StampedLock lock = new StampedLock(); Thread thread = new Thread(()->{ // 获取写锁 lock.writeLock(); // 永远阻塞在此处,不释放写锁 LockSupport.park(); }); thread.start(); // 保证 thread 获取写锁 Thread.sleep(100); Thread thread2 = new Thread(()-> // 阻塞在悲观读锁 lock.readLock() ); thread2.start(); // 保证 thread2 阻塞在读锁 Thread.sleep(100); // 中断线程 thread2,导致 thread2 CPU 飙升 thread2.interrupt(); thread2.join();}
以上代码中,线程一先获取到锁,之后阻塞,并未释放锁,而线程二阻塞在 readLock() 读锁时,收到了中断请求 interrupt(),但并未正确处理中断异常,因此线程会陷入无限循环中,试图从中断状态中恢复,这就会导致 CPU 使用率一直飙升。
本文链接:http://www.28at.com/showinfo-26-101702-0.html为什么StampedLock会导致CPU100%?
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com