一、什么是ReadWriteLock
ReadWriteLock是Java中的一种锁机制,它允许多个线程同时对某个共享资源进行读操作,但在写操作时必须独占该资源。相比于传统的同步锁(synchronized),ReadWriteLock提供了更细粒度的控制,可以大大提高并发性能。
在ReadWriteLock中,有两种锁:读锁和写锁。读锁可以被多个线程同时持有,但写锁只能被一个线程独占。当一个线程获得写锁时,其他线程不能获得读锁或者写锁,只能等待写锁释放。在读操作比写操作频繁的情况下,使用ReadWriteLock可以提高系统的并发性能。
以下是一个简单的Java示例代码,使用ReadWriteLock实现对共享资源的读写访问控制:
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class SharedResource {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private String data;
public void writeData(String newData) {
lock.writeLock().lock();
try {
// 写操作
data = newData;
} finally {
lock.writeLock().unlock();
}
}
public String readData() {
lock.readLock().lock();
try {
// 读操作
return data;
} finally {
lock.readLock().unlock();
}
}
}
在上面的代码中,我们通过添加ReadWriteLock实例来控制对data变量的并发访问。在writeData方法中,我们获取了写锁,执行写操作,并释放锁。在readData方法中,我们获取了读锁,执行读操作,并释放锁。这样,在多线程环境下,对于同一个SharedResource实例,任何时候只有一个线程可以写入data,但同时可以有多个线程同时读取data。这样就保证了线程安全性和并发性。
二、什么是StampedLock
StampedLock是Java 8中引入的一种新型锁,它提供了三种模式:读、写和乐观读。与ReentrantReadWriteLock相比,StampedLock使用更加灵活和高效,并且可以防止ABA问题的发生。
StampedLock的使用类似于ReadWriteLock,但有一些区别。StampedLock不支持可重入性,因此在同一个线程中对StampedLock进行多次加锁会导致死锁。此外,在使用StampedLock时需要注意控制锁的版本号,以避免ABA问题。
下面是一个使用StampedLock的示例代码:
import java.util.concurrent.locks.StampedLock;
public class StampedLockExample {
private final StampedLock lock = new StampedLock();
private double x;
private double y;
public void move(double deltaX, double deltaY) {
long stamp = lock.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
lock.unlockWrite(stamp);
}
}
public double distanceFromOrigin() {
long stamp = lock.tryOptimisticRead();
double currentX = x;
double currentY = y;
if (lock.validate(stamp)) {
return Math.sqrt(currentX * currentX + currentY * currentY);
} else {
stamp = lock.readLock();
try {
currentX = x;
currentY = y;
return Math.sqrt(currentX * currentX + currentY * currentY);
} finally {
lock.unlockRead(stamp);
}
}
}
}
在这个示例中,StampedLockExample
类有两个私有成员变量x
和y
,它们表示一个二维平面上的点。move()
方法用于更新这个点的位置,在方法内部使用writeLock()
获取写锁,以确保线程安全。distanceFromOrigin()
方法用于计算该点与原点之间的距离,并且使用了乐观读取模式来提高性能。如果验证成功,就直接返回计算结果;否则,需要使用readLock()
获取读锁并重新计算。最后记得释放锁。
三、ReadWriteLock 和 StampedLock的区别和联系
ReadWriteLock和StampedLock都是Java中用于多线程读写操作的锁机制。
区别:
-
功能不同:ReadWriteLock提供了一种典型的读写锁定,允许多个线程同时读取共享数据,但只允许一个线程写入共享数据,而StampedLock除了支持读和写的锁定模式之外,还支持另外一种乐观锁模式,这种模式下所有的操作都不会阻塞线程。
-
性能不同:StampedLock比ReadWriteLock更轻量级,在低并发访问下性能更好,但在高并发状态下性能不如ReadWriteLock。
联系:
-
都是用于多线程读写操作的锁机制。
-
两者都支持可重入性和公平性。
-
都可以使用tryLock()方法尝试获取锁,如果获取不到也不会阻塞线程。
-
都是JDK中提供的线程安全的锁机制。