AQSアプリケーション-R e n t rantReadWriteLock(読み書きロックを再読み込み可能)
7952 ワード
生活する
今日は土曜日、晴れ、残業、よかった!
_____
今日は読み書きロックを再読み込みできることを検討します.まず明確にしなければならないのは、前に研究した再ロック可能なReentrantLockは、実際には反発ロックであり、同じ時点で1つのスレッドだけがリソースを取得することを保証し、書くこと、読むこと、読むこと、読むこと、書くことのどのシーンも反発していることです.この反発ロックは、一般的な高同時シーンでは、低スループットの問題を示す.実際には,高同時の実際のシーンでは,読み取りの頻度が書き込みよりはるかに高く,読み取り自体がデータを修正することなく読み取りのみを行うため,読み取りの操作を共有し,書き込み操作を独占することが望ましい.これが読み書きロックの役割です.その特性は、1つのリソースが複数の読み取り操作で同時にアクセスされたり、1つの書き込み操作で独占されたりすることです.しかし、両者は同時にアクセスできません.
ソースコード
初対面ReentrantReadWriteLock
ReentrantReadWriteLockはReentrantLockから継承されていないし、Lockインタフェースも実現されていないが、独自のReadWriteLockインタフェースを実現している.
リードロック解析
リードロックロックロック()の方法では、次のような重要な方法があります.
書き込みロックロックロック()方法:
後記
明日は日曜日だから朝寝坊してもいいですよ.
今日は土曜日、晴れ、残業、よかった!
_____
今日は読み書きロックを再読み込みできることを検討します.まず明確にしなければならないのは、前に研究した再ロック可能なReentrantLockは、実際には反発ロックであり、同じ時点で1つのスレッドだけがリソースを取得することを保証し、書くこと、読むこと、読むこと、読むこと、書くことのどのシーンも反発していることです.この反発ロックは、一般的な高同時シーンでは、低スループットの問題を示す.実際には,高同時の実際のシーンでは,読み取りの頻度が書き込みよりはるかに高く,読み取り自体がデータを修正することなく読み取りのみを行うため,読み取りの操作を共有し,書き込み操作を独占することが望ましい.これが読み書きロックの役割です.その特性は、1つのリソースが複数の読み取り操作で同時にアクセスされたり、1つの書き込み操作で独占されたりすることです.しかし、両者は同時にアクセスできません.
ソースコード
初対面ReentrantReadWriteLock
ReentrantReadWriteLockはReentrantLockから継承されていないし、Lockインタフェースも実現されていないが、独自のReadWriteLockインタフェースを実現している.
//
Lock readLock();
//
Lock writeLock();
読み書きロックを作成する場合は、コンストラクタを簡単に見てください.//
public ReentrantReadWriteLock() {
this(false);
}
// fair true
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
// Sync AQS,FairSync NonFairSync Sync, 。 、
ReentrantLockの具体的な実装から,その独占性と再入性はAQS内のstate変数に対する操作によって実現されることが分かった.ReentrantReadWriteLockでは読み書きの2つの操作を実現する必要があるため,stateというint変数を上位16ビットと下位16ビットに分ける.高16ビットはリードロック使用量、低16ビットはライトロック使用量である.リードロック解析
リードロックロックロック()の方法では、次のような重要な方法があります.
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
// ( ) , -1,
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
int r = sharedCount(c);
//
//1、 : 、 , , true,
// false,
//2、
//3、CAS +1
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
// , +1
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
//rh
HoldCounter rh = cachedHoldCounter;
// , ThreadLoccal
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);
}
, AQS , SIGNAL , 。
リードロックunLock()メソッド 。。
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))
// Releasing the read lock has no effect on readers,
// but it may allow waiting writers to proceed if
// both read and write locks are now free.
return nextc == 0;
}
}
書き込みロック解析書き込みロックロックロック()方法:
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
// false
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;
}
書き込みロックunlockメソッド ,
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
ケースpublic class RRWLTest {
public static void main(String[] args) {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
CountDownLatch latch = new CountDownLatch(1);
new Thread(new Test(readLock, null, 0, "A", latch)).start();
new Thread(new Test(null, writeLock, 2000, "B", latch)).start();
new Thread(new Test(readLock, null, 0, "C", latch)).start();
new Thread(new Test(null, writeLock, -500, "D", latch)).start();
new Thread(new Test(readLock, null, 0, "E", latch)).start();
new Thread(new Test(readLock, null, 0, "F", latch)).start();
new Thread(new Test(null, writeLock, 600, "G", latch)).start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
latch.countDown();
}
static class Test implements Runnable{
public static volatile int account =0;
private ReentrantReadWriteLock.ReadLock readLock;
private ReentrantReadWriteLock.WriteLock writeLock;
private int money;
private String name;
private CountDownLatch latch;
@Override
public void run() {
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null!=readLock) {
readLock.lock();
System.out.println(String.format("name:%s, :%s", name,account));
readLock.unlock();
}
else {
writeLock.lock();
account+=money;
if(money>0) {
System.out.println(String.format("name:%s, :%s, :%s", name,money,account));
}else {
System.out.println(String.format("name:%s, :%s, :%s", name,-money,account));
}
writeLock.unlock();
}
}
public Test(ReadLock readLock, WriteLock writeLock, int money, String name, CountDownLatch latch) {
super();
this.readLock = readLock;
this.writeLock = writeLock;
this.money = money;
this.name = name;
this.latch = latch;
}
}
}
実行結果:name:B、預金:2000、残高:2000 name:D、引き出し:500、残高:1500 name:G、預金:600、残高:2100 name:C、照会残高:2100 name:F、照会残高:2100 name:A、照会残高:2100 name:E、照会残高:2100後記
明日は日曜日だから朝寝坊してもいいですよ.