Java ArrayBlockingQueue取源

时间:2018-05-30 03:50:08

标签: java multithreading concurrency locking

当我阅读ArrayBlockingQueue.take方法的源代码时,我遇到了问题。

我认为然后两个线程同时调用take方法,只有一个线程可以成功获取锁定,而另一个线程将等待该行的锁定:lock.lockInterruptibly(); 这是take的源代码:

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}

但是当我对这两个线程进行线程转储时,我发现两个线程都成功锁定并在线等待:notEmpty.await();(因为队列为空) 这是线程转储:

  

“test-thread-18”#6357守护进程prio = 5 os_prio = 0 tid = 0x00007f8f54543000 nid = 0x58ef等待条件[0x00007f901bc70000]      java.lang.Thread.State:WAITING(停车)     在sun.misc.Unsafe.park(原生方法)      - 停车等待< 0x00007f93ae695410> (java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject)     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)     at java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject.await(AbstractQueuedSynchronizer.java:2039)     at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:403)     at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)     at java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:617)     在java.lang.Thread.run(Thread.java:745)

     

“test-thread-17”#6356守护程序prio = 5 os_prio = 0 tid = 0x00007f8f54542000 nid = 0x58ee等待条件[0x00007f901beb9000]      java.lang.Thread.State:WAITING(停车)     在sun.misc.Unsafe.park(原生方法)      - 停车等待< 0x00007f93ae695410> (java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject)     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)     at java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject.await(AbstractQueuedSynchronizer.java:2039)     at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:403)     at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)     at java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:617)     在java.lang.Thread.run(Thread.java:745)

那么,为什么两个不同的线程可以同时获得相同的锁? 我的理解有什么问题?

1 个答案:

答案 0 :(得分:3)

只有一个线程可以同时保存ReentrantLock

notEmptyCondition对象,当前线程会在调用Condition.await()时解除锁定:

  

使当前线程等待,直到发出信号或   中断。与此条件关联的锁定是原子   发布,当前线程因线程调度而被禁用   目的和谎言一直处于休眠状态,直到四件事之一发生:

     
      
  • 其他一些线程调用此Condition和的signal()方法   当前线程恰好被选为要被唤醒的线程;
  •   
  • 或其他一些线程为此调用signalAll()方法   条件;
  •   
  • 或其他一些线程中断当前线程,和   支持线程暂停的中断;    - 或者A"虚假的唤醒"   发生。
  •   
     

在所有情况下,在此方法之前可以返回当前线程   必须重新获取与此条件相关的锁定。当。。。的时候   线程返回它保证保持此锁定。