JavaのロックとReentrantLock

20594 ワード

文書ディレクトリ
  • Lock
  • 再ロック可能ReentrantLock
  • 再入力可能分析
  • フェアロックと非フェアロック分析
  • は、自身が再入可能なロック
  • を実現する.
    Lock
    ロックはJDK 1です.5の後に提供されます.Java構文レベルのロックです.ロックはlockを使用します.lock()は、ロックを解除するlockを使用する.unlock(). unlock, finally は、ロック後にコードに異常が発生した場合、ロックを解放しないので注意してください. synchronized :
  • synchronizedのロックとロック解除はすべてJVMによって実現され、異常が発生すると自動的にロックが解除され、ロックは手動でロックを解除する必要があり、finallyで解放しなければならない.
  • Lockは割り込みロックを実現することができ、ロックを取得したスレッドが割り込まれると、割り込み異常が投げ出され、同時にロックが解放される.
  • Lockは、非ブロック方式を使用して、ロックを取得しようとすることができ、取得されなければ、直接戻ることができる.synchronizedはロックが取れないとそこに詰まってしまいます.
  • Lockはタイムアウトを使用してロックを取得することができ、指定された時間内にロックを取得せずに直接戻ります.

  • ロックの最下層はAbstractQueuedSynchronizerによって実現された.
    再ロック可能ReentrantLock
    さいにゅうかのうぶんせき
    synchronizedはステルス再入可能であり,現在ロックを取得しているスレッドは,直接ロックを再取得することができる.
    ReentrantLockはAQSを利用して再入力可能な効果分析を実現する:
    スレッドが同期リソースを取得するたびにstate+1、スレッドが同期リソースを解放するたびにstate-1.stateが0の場合、スレッドは同期リソースを完全に解放します.
  • nonfairTryAcquire
  • final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        //         
        if (c == 0) {
            //      0,  CAS      ,                  
            //         
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            //              ,     ,state+1
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
    
  • tryRelease()
  • protected final boolean tryRelease(int releases) {
        //      ,state 1
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        // state 0             ,             
        if (c == 0) {
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }
    

    フェアロックと非フェアロックの分析
    フェアロックは、ロックが解放されると、より長い待ち時間を持つスレッドがロックを優先することを意味します.ReentrantLockの実装では,スレッドがロックを取得しようとすると,同期キューに前駆ノードがあるか否かを判断し,あるとロックを取得できない.
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            // hasQueuedPredecessors                       ,      false,     true
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
    

    しかし、非公平ロックの効率は公平ロックよりも高い.公平ロックの実現では、現在のスレッドが呼び覚まされた後にロックを取ろうとすると、最初のスレッドが現在のスレッドではないことを待つと、今回のロックを取る機会を浪費し、スレッドは再びブロック状態に入るからだ.
    自分で再ロックを実現
    public class MyReentrantLock implements Lock {
    
        private static final Sync sync = new Sync();
    
        private final static class Sync extends AbstractQueuedSynchronizer {
            //      
            @Override
            protected boolean tryAcquire(int arg) { 
                //         
                int state = getState();
                //           ,          
                if (state == 0) {
                    if (compareAndSetState(0,arg)) {
                        setExclusiveOwnerThread(Thread.currentThread());
                        return true;
                    }
                } else {
                    //          ,            
                    if (getExclusiveOwnerThread() == Thread.currentThread()) {
                        //           state + arg(       ,    )
                        setState(state + arg);
                        return true;
                    }
                }
                return false;
    
            }
      		//       
            @Override
            protected boolean tryRelease(int arg) {
                int newState = getState() - arg;
                if (newState < 0) {
                    throw new IllegalMonitorStateException();
                }
                //            
                if (newState == 0) {
                    setState(0);
                    setExclusiveOwnerThread(null);
                    return true;
                }
                //        ,      true
                setState(newState);
                return false;
            }
        }
    
        @Override
        public void lock() {
            sync.acquire(1);
        }
    
        @Override
        public void unlock() {
            sync.release(1);
        }
        ... //   Lock       
    }