文章目录
- 前言
- StampedLock 有三种模式:悲观读锁、乐观读锁和写锁。
-
- 1. 悲观读锁:
- 2. 乐观读锁:
- 3. 写锁:
- 代码示例
- 总结
前言
在多线程编程中,并发控制是确保数据一致性和避免冲突的关键。ReentrantReadWriteLock 是 Java 中的一个常用工具,它提供了读写锁的功能,使得多个线程可以同时读取共享资源,但在写入时则需要独占式的访问。然而,在某些情况下,ReentrantReadWriteLock 的性能可能并不理想。为了解决这个问题,Java 8 引入了一个新的并发工具 StampedLock。
StampedLock 是一种改进的读写锁,它在没有写操作只有读操作的场景下,支持不加读锁而直接进行读操作,从而最大程度地提升读的效率。只有在发生过写操作之后,再加读锁才能进行读操作。这种机制使得 StampedLock 在某些场景下比ReentrantReadWriteLock 更加高效。
StampedLock 有三种模式:悲观读锁、乐观读锁和写锁。
1. 悲观读锁:
与 ReentrantReadWriteLock 的读锁类似,多个线程可以同时获取悲观读锁。这是一个共享锁,允许多个线程同时读取共享资源。
2. 乐观读锁:
相当于直接操作数据,不加任何锁。在操作数据前并没有通过 CAS 设置锁的状态,仅仅通过位运算测试。如果当前没有线程持有写锁,则简单地返回一个非 0 的 stamp 版本信息。返回 0 则说明有线程持有写锁。获取该 stamp 后在具体操作数据前还需要调用 validate 方法验证该 stamp 是否己经不可用。
3. 写锁:
与 ReentrantReadWriteLock的写锁类似,写锁和悲观读锁是互斥的。虽然写锁与乐观读锁不会互斥,但是在数据被更新之后,之前通过乐观读锁获得的数据已经变成了脏数据。这是一个排它锁或者独占锁,某时只有一个线程可以获取该锁。
StampedLock 的读写锁都是不可重入锁,所以在获取锁后释放锁前不应该再调用会获取锁的操作,以避免造成调用线程被阻塞。
在实际应用中,StampedLock 可以用于那些读操作远多于写操作的场景,例如缓存系统、数据报表生成等。在这些场景中,StampedLock 可以显著提高并发性能,同时保证数据的一致性和安全性。
代码示例
import java.util.concurrent.locks.StampedLock; public class StampedLockExample { private int inventory = 100; // 初始库存为100 private final StampedLock lock = new StampedLock(); // 扣减库存操作 public void decreaseInventory(int quantity) { long stamp = lock.writeLock(); // 获取写锁 try { if (inventory >= quantity) { inventory -= quantity; // 扣减库存 System.out.println("成功减少库存 " + quantity + ", 当前的库存量: " + inventory); } else { System.out.println("未能减少库存,库存不足"); } } finally { lock.unlockWrite(stamp); // 释放写锁 } } // 获取当前库存 public int getInventory() { long stamp = lock.tryOptimisticRead(); // 乐观读锁 int currentInventory = inventory; if (!lock.validate(stamp)) { // 检查乐观读锁是否有效 stamp = lock.readLock(); // 乐观读锁无效,转为悲观读锁 try { currentInventory = inventory; // 获取当前库存 } finally { lock.unlockRead(stamp); // 释放读锁 } } return currentInventory; // 返回当前库存 } public static void main(String[] args) { StampedLockExample manager = new StampedLockExample(); // 多个线程同时扣减库存 Thread t1 = new Thread(() -> { manager.decreaseInventory(20); // 线程1扣减库存 System.out.println(manager.getInventory()); }); Thread t2 = new Thread(() -> { manager.decreaseInventory(50); // 线程2扣减库存 System.out.println(manager.getInventory()); }); t1.start(); t2.start(); } }
总结
StampedLock 是一种高效的并发锁机制,它通过改进读写锁的机制来提高并发性能。在读多写少的场景中,StampedLock
可以提供更好的性能表现。然而,使用 StampedLock 也需要注意避免死锁和其他并发问题,以确保程序的正确性和稳定性。