2016-08-23 4 views
2

これは愚かな質問かもしれませんが、ReentrantLockを2つの別のスレッドがこのクラスで使用できる理由を理解できません(ArrayBlockingQueueスレッドとロック)をプレイする:ArrayBlockingQueueの2つのスレッドでReentrantLockを取得できる理由

class SampleThreadSafeQueue { 

     private ReentrantLock lock = new ReentrantLock(); 
     private List<Integer> list = new ArrayList<>(); 
     private Condition notEmpty; 
     private Condition notFull; 
     private volatile int count; 

     public SampleThreadSafeQueue() { 
      notEmpty = lock.newCondition(); 
      notFull = lock.newCondition(); 
     } 

     public int take() { 
      try { 
       lock.lock(); 
       System.out.println(Thread.currentThread().getName() +": acquired lock in take()"); 
       while (count == 0) { 
        notEmpty.await(); 
       } 

       return extract(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
       return 0; 
      } finally { 
       System.out.println(Thread.currentThread().getName() +": released lock for take()"); 
       lock.unlock(); 
      } 
     } 

     private int extract() { 
      int index = count <= 0 ? 0 : count - 1; 
      Integer integer = list.get(index); 
      list.remove(index); 
      count--; 
      list.clear(); 
      notFull.signal(); 
      return integer; 
     } 

     public void put(int value) { 
      try { 
       lock.lock(); 
       System.out.println(Thread.currentThread().getName() +": acquired lock in put()"); 
       while (!list.isEmpty()) { 
        notFull.await(); 
       } 
       Thread.sleep(3000); // let's assume it takes 3 secs to add value 
       insert(value); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } finally { 
       System.out.println(Thread.currentThread().getName() +": released lock for put()"); 
       lock.unlock(); 
      } 
     } 


     private void insert(int value) { 
      list.add(value); 
      count = list.size(); 
      notEmpty.signal(); 
     } 
    } 

私はコンソールでこの結果を受け取る:

pool-1-thread-1: acquired lock in put() 
pool-1-thread-1: released lock for put() 
pool-1-thread-1: acquired lock in put() - this guy has taken the lock 
pool-1-thread-2: acquired lock in take() - that guy has taken the lock as well! wtf? 
pool-1-thread-2: released lock for take() 
Value = 0 
pool-1-thread-2: acquired lock in take() 
pool-1-thread-1: released lock for put() 
pool-1-thread-1: acquired lock in put() 
pool-1-thread-2: released lock for take() 
Value = 1 
pool-1-thread-1: released lock for put() 
pool-1-thread-1: acquired lock in put() 
pool-1-thread-2: acquired lock in take() 
pool-1-thread-2: released lock for take() 
Value = 2 
... 

私は条件が私はしばらくのサイクルで使用しますが、論理的にそれが起こるん理由を理解することができないからだと疑います。 あなたの説明に感謝します。ありがとう!

答えて

1

あなたには、いくつかのロックから入手したConditionawait()を呼び出すと、あなたのスレッドがロックを解除し、Conditionが(signal()またはsignalAll()により)別のスレッドから通知されるまで停止します。

したがって、スレッド1はロックを取得した後、await()を呼び出し、スレッド2によって最近取得されたロックを解放する待機モードに切り替わります。スレッド2が完了すると、スレッド1に通知します(signal())ロックを解除します。ロックはすぐにスレッド1によって再獲得され、起動して作業を継続し、最後にロックを解除します。

その後、若干異なる順序で繰り返します。

1

あなたが理解する必要がどのような条件の文書でhttp://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html

を見てみましょう条件(のawait、信号は)同期(通知、待つ)のようであるということです。 await()を呼び出すと、ロックの保留が解除されます。 (あなたはまだlock.unlock() thoに電話しなければならない)。 put()notFull.signal()をトリガーするtake()を待ち、put()notEmpty.signal()をトリガーするのを待ってtake()を待ちます。ロックは、await()コールで直接同期してしまい、慣れていないようなlock.lock()にはなりません。

これは文書化の例です:

class BoundedBuffer { 
    final Lock lock = new ReentrantLock(); 
    final Condition notFull = lock.newCondition(); 
    final Condition notEmpty = lock.newCondition(); 

    final Object[] items = new Object[100]; 
    int putptr, takeptr, count; 

    public void put(Object x) throws InterruptedException { 
    lock.lock(); 
    try { 
     while (count == items.length) 
     notFull.await(); 
     items[putptr] = x; 
     if (++putptr == items.length) putptr = 0; 
     ++count; 
     notEmpty.signal(); 
    } finally { 
     lock.unlock(); 
    } 
    } 

    public Object take() throws InterruptedException { 
    lock.lock(); 
    try { 
     while (count == 0) 
     notEmpty.await(); 
     Object x = items[takeptr]; 
     if (++takeptr == items.length) takeptr = 0; 
     --count; 
     notFull.signal(); 
     return x; 
    } finally { 
     lock.unlock(); 
    } 
    } 
} 
関連する問題