并发编程系列之StampedLock使用
Posted smileNicky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程系列之StampedLock使用相关的知识,希望对你有一定的参考价值。
1、什么是StampedLock?
- StampedLock,也即邮戳锁,是jdk8中推出的对读写锁的缺点进行改进的邮戳锁,它推出了乐观读写来改进大量并发读,少量写的情况的性能。
- StampedLock是不可重入的,使用时需特别注意。
2、StampedLock三种模式
StampedLock有三种模式,读写 可以 相互转换:
- Writing:写模式
- Reading:悲观读模式
- Optimistic Reading:乐观读模式
一个StampedLock状态是由票据和模式两个部分组成的,锁获取方法返回一个数字作为票据stamp,它用相应的锁状态表示并控制访问,数字0表示没有写锁被授权访问。在读锁上分为悲观锁和乐观锁。
3、StampedLock相关API
- 获得独占写锁:
long writeLock()
:阻塞式获取锁long tryWriteLock()
:尝试获取锁,如返回0表示没有获得锁long tryWriteLock(long time, TimeUnit unit)
:尝试获取锁,如返回0表示没有获得锁long writeLockInterruptibly()
:可中断式获取读锁
- 释放写锁:
void unlockWrite(long stamp)
boolean tryUnlockWrite
:尝试释放写锁,如果线程持有写锁,释放,返回true,否则返回false
- 获取读锁:
long readLock()
:阻塞式非独占获取锁 。long tryReadLock()
:尝试获得写锁,如返回0表示没有获得锁long tryReadLock(long time , TimeUnit unit)
:尝试获得写锁,如返回0表示没有获得锁long readLockInterruptibly()
:可中断式获取读锁
- 释放读锁:
void unlockRead (long stamp)
boolean tryUnlockRead()
:尝试释放对读锁的一个持有;如果持有,则释放,返回true,否则返回false
- 获取乐观读锁
long tryOptimisticRead()
:当被其它线程占用时,将返回0。
- 转换模式:
long tryConvertToOptimisticRead(long stamp)
long tryConvertToReadLock(long stamp)
long tryConvertToWriteLock(long stamp)
- 判断锁的当前状态(模式)
boolean isWriteLocked()
boolean isReadLocked()
- 为了优化老代码中的读写锁,StampedLock提供了三个方法将自身转为读写锁:
Lock asReadLock()
Lock asWriteLock()
ReadWriteLock asReadWriteLock()
- 其它API
boolean validate(long stamp)
:参数为乐观锁票据void unlock(long stamp)
:释放锁,如果锁的状态匹配给入的stamp,释放锁的对应模式
StampedLock例子
例子:使用StampedLock 来做缓存的并发控制,有缓存put和get方法:
import org.springframework.util.StringUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.StampedLock;
public class StampedLockCache
private final Map<Integer , String> cache = new ConcurrentHashMap<>();
private final StampedLock stampedLock = new StampedLock();
public void put(Integer key , String value)
// 上写锁
long stamp = stampedLock.writeLock();
try
cache.put(key , value);
finally
// 释放写锁
stampedLock.unlockWrite(stamp);
public String get(Integer key)
// 先获取乐观锁
long stamp = stampedLock.tryOptimisticRead();
// 先尝试通过乐观锁方式读取数据
String value = cache.get(key);
// 校验是否被其它线程修改过,true:表示未修改 false:修改过,表示需要加悲观锁
if (!stampedLock.validate(stamp))
// 上悲观锁
stamp = stampedLock.readLock();
try
value = cache.get(key);
finally
stampedLock.unlock(stamp);
return value;
public String putIfNotExist(Integer key , String value)
long stamp = stampedLock.readLock();
String currentValue = cache.get(key);
try
while (StringUtils.isEmpty(currentValue))
// 尝试锁升级,读锁升级为写锁
long wstamp = stampedLock.tryConvertToWriteLock(stamp);
if (wstamp != 0L) // 不为0表示锁升级成功
stamp = wstamp;
currentValue = value;
// 数据写到缓存里
cache.put(key , value);
break;
else // 锁升级失败
// 释放读锁
stampedLock.unlockRead(stamp);
stamp = stampedLock.writeLock();
finally
// 释放所有的锁
stampedLock.unlock(stamp);
return currentValue;
附录参考资料
以上是关于并发编程系列之StampedLock使用的主要内容,如果未能解决你的问题,请参考以下文章
JUC并发编程 共享模式之工具 JUC 读写锁 StampedLock -- 介绍 & 使用
一文彻底理解并发编程中非常重要的票据锁——StampedLock
一文彻底理解并发编程中非常重要的票据锁——StampedLock