目录
ReentrantReadWriteLock 与StampedLock的区别:
ReentrantReadWriteLock 与StampedLock的区别:
ReentrantReadWriteLock
ReentrantReadWriteLock 实例代码:
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ThreadTest {
static int aba =2;
public static void main(String[] args) {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
//写锁是独占模式
new Thread(()->{
try {
writeLock.lock();
System.out.println("这是写锁");
aba=3;
aba = 2;
System.out.println("aba:"+aba);
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
}finally {
writeLock.unlock();
}
}).start();
//两个读锁里的内容几乎是同时打印
new Thread(()->{
try {
readLock.lock();
System.out.println("这是读锁1");
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
}finally {
readLock.unlock();
}
}).start();
new Thread(()->{
try {
readLock.lock();
System.out.println("这是读锁2");
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
}finally {
readLock.unlock();
}
}).start();
}
}
ReentrantReadWriteLock源码解读:
并说明以下三个问题:
1.锁降级问题;
2.公平队列;
3.非公平队列;
//读锁获取锁 高16位保存读锁
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
//锁的降级;为了保证可见性
//当其他线程写锁需要占用很长时间时,对于高响应的业务需求并不允许;完成部分写操作后,退而使用读锁降级,来允许响应其他进程的读操作。只有当全部事务完成后才真正释放锁
//思想:写的时候可以读
doAcquireShared(arg);
}
private void doAcquireShared(int arg) { //将遍历当前节点前的节点,有写锁的打断;打断后队列的读锁就可以获取锁了
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();//写锁打断操作
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())//判断写锁是否打断成功
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current) //其他线程含有写锁(独占锁),返回失败
return -1;
int r = sharedCount(c); //获取持有的共享锁数量r
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {//r小于共享锁最大值,则进行读锁自增操作
if (r == 0) { //判断当前是不是第一个读锁
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh); //保存当前线程获取读锁的次数
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
//如果当前线程是重入读锁则放行
} else if (readerShouldBlock()) {
// Make sure we're not acquiring read lock reentrantly
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
if (rh.count == 0)
return -1;
}
}
if (sharedCount(c) == MAX_COUNT)//共享锁使用达到最大值,抛出异常
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0) //保存当前线程获取读锁的次数
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return 1;
}
}
}
//读锁释放
public void unlock() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
//写锁加锁 低16位保存写锁
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//尝试获取,获取失败后入队,入队失败则interrupt当前线程
selfInterrupt();
}
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {//状态不为0,说明锁已经被占用
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())//判断是否是当前线程获取
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT) //判断锁是否已经被用完
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current); //设置当前线程获取独占锁
return true;
}
//写锁的释放
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); //唤醒后续节点
return true;
}
return false;
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null); //设置当前独占的线程为Null
setState(nextc);//设置state为0
return free;
}
//公平队列 读锁写锁都是要排队的
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
//非公平队列 写锁竞争获取锁;写锁的优先级高于读锁;假如队列中有写锁,写锁优先
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
// 非公平下不考虑排队,因此写锁可以竞争获取
return false; // writers can always barge
}
final boolean readerShouldBlock() {
// 这里实际上是一个优先级,如果队列中头部元素时写锁,那么读锁需要等待,避免写锁饥饿。
return apparentlyFirstQueuedIsExclusive();
}
}
StampedLock :
对ReadtrantReadWriteLock的改进,乐观读模式(相当于无锁状态)读的时候允许写入,提高并发;
StampedLock 应用实例:
import java.util.concurrent.locks.StampedLock;
public class StampLockTest {
StampedLock stampedLock = new StampedLock();
private int state;
public StampLockTest(int state) {
this.state = state;
}
public StampLockTest() {
}
public void write() {
long stamp = stampedLock.writeLock();
try {
state++;
state--;
System.out.println("写完后的state:"+state);
} catch (Exception e) {
} finally {
stampedLock.unlockWrite(stamp);
}
}
public void read() {
//乐观读取适用于读多写少的情况
long stamp = stampedLock.tryOptimisticRead();//获取一个乐观读锁;;;返回一个版本号
int state1 = state;//乐观读取
System.out.println("乐观读:"+state1);
//验证当前的版本号与最开始的是否一致,不一致表示中间有了写的操作
if (!stampedLock.validate(stamp)) {//读取数据时有写的操作;;悲观读
try {
stampedLock.readLock();
int state2 = state;
System.out.println("悲观读:"+state2);
} catch (Exception e) {
} finally {
stampedLock.unlockRead(stamp);
}
}
}
}