1.ReentrantReadWriteLock
当读取操作远远高于写操作时,这时候使用读写锁让读-读可以并发(即然多个线程的读取是可以并行的),提高性能。
类似于数据库中的 select ... from ... lock in share mode
提供一个数据容器类,内部分别使用读锁保护数据的read()方法,写锁保护数据的write()方法
注意事项:
1.读锁不支持条件变量,写锁支持
2.重入时升级不支持,即同一个线程第一次获取的是读锁,然后又去获取写锁,会导致获取写锁永久等待(阻塞住了)
如下:
3.重入时支持降级:即先获取写锁,然后获取读锁。
扫描二维码关注公众号,回复:
14734401 查看本文章
2.StampedLock
该类自JDK8加入,是为了进一步优化读性能,它的特点是在使用读锁、写锁时都必须配合戳使用
加解读锁
long stamp = lock.readLock();
lock.unlockRead(stamp);
加解写锁
long stamp = lock.writeLock();
lock.unlockWrite(stamp);
乐观读,StampedLock支持tryOptimisticRead()方法(乐观读),读取完毕后需要做一次戳校验,如果校验通过,表示这期间确实没有写操作,数据可以安全使用,如果校验没有通过,需要重新获取读锁,保证数据安全。
long stamp = lock.tryOptimisticRead();
//验戳
if(!lock.validate(stamp)){
//锁升级
}
StampedLock的乐观读和普通的读锁的区别是:普通的读锁在多个线程同时读的时候,所有的写操作会被阻塞,而 StampedLock 提供的乐观读,是允许线程获取写锁的,也就是说不是所有的写操作都被阻塞,也就是说乐观读其实是无锁的。那具体要如何使用呢?我们来看一个简单的例子
public class DataContainerStamped {
private int data;
private final StampedLock lock = new StampedLock();
public DataContainerStamped(int data) {
this.data = data;
}
public int read(int readTime) throws InterruptedException {
long stamp = lock.tryOptimisticRead();
System.out.println("optimistic read locking ..."+stamp);
Thread.sleep(readTime);
//戳没有改变,即这段时间内没有其他线程进行写操作
if (lock.validate(stamp)){
System.out.println("read finish... "+stamp);
return data;
}
//锁升级 - 读锁
System.out.println("updating to read lock... "+stamp);
try{
stamp = lock.readLock();
System.out.println("read lock... "+stamp);
Thread.sleep(readTime);
System.out.println("read finish... "+stamp);
return data;
}finally {
System.out.println("read unlock "+stamp);
//释放悲观读锁
lock.unlockRead(stamp);
}
}
public void write(int newData) throws InterruptedException{
long stamp = lock.writeLock();
System.out.println("write lock... "+stamp);
try {
Thread.sleep(2000);
this.data = newData;
} finally {
System.out.println("write lock... "+stamp);
lock.unlockWrite(stamp);
}
}
}
比读写锁(ReadWriteLock)更快的锁(StampedLock)_weihubeats的博客-CSDN博客_比读写锁更快的锁
注意
* StampedLock 不支持条件变量(ReentrantReadWriteLock写锁支持)
* StampedLock 不支持可重入(ReentrantReadWriteLock支持降级不支持升级)