AQSアプリケーション-R e n t rantReadWriteLock(読み書きロックを再読み込み可能)

7952 ワード

生活する
今日は土曜日、晴れ、残業、よかった!
_____
今日は読み書きロックを再読み込みできることを検討します.まず明確にしなければならないのは、前に研究した再ロック可能な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
後記
明日は日曜日だから朝寝坊してもいいですよ.