Java ArrayBlockingQueue взять источник - PullRequest
0 голосов
/ 30 мая 2018

Когда я читал исходный код метода 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.AbstractQueuedSject) $в java.util.concurrent.locks.LockSupport.park (LockSupport.java:175) в java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject.await (AbstractQueuedSynchronizer.java:2039) в java.util.concurrent.ArrayBlockingQueue.take (ArrayBlockingQueue.java:403) в java.util.concurrent.ThreadPoolExecutor.getTask (ThreadPoolExecutor.java:1067) в java.utiler.con(ThreadPoolExecutor.java:1127) в 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) в java.util.concurrent.locks.LockSupport.park (LockSupport.java:175) в java.rentglox$ ConditionObject.await (AbstractQueuedSynchronizer.java:2039) в java.util.concurrent.ArrayBlockingQueue.take (ArrayBlockingQueue.java:403) в java.util.concurrent.ThreadPoolExecutor.getTask (ThreadPoolExecutor.java:1067) в java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1127) в java.util.concurrent.ThreadPoolExecutor: рабочий класс.lang.Thread.run (Thread.java:745)

Итак, почему два разных потока могут получить одну и ту же блокировку одновременно?Что не так с моим пониманием?

1 Ответ

0 голосов
/ 30 мая 2018

Только одна нить может одновременно хранить ReentrantLock.

notEmpty является объектом Condition, текущий поток снимет блокировку при вызове Condition.await():

Причинытекущий поток, чтобы ждать, пока он не будет сигнализирован или прерван.Блокировка, связанная с этим условием, является атомно освобожденной , и текущий поток отключается для целей планирования потока и остается неактивным до тех пор, пока не произойдет одно из четырех:

  • Какой-то другой поток вызывает сигнал() метод для этого условия и текущий поток выбирается в качестве потока, который должен быть пробужден;
  • или какой-то другой поток вызывает метод signalAll () для этого условия;
  • или какой-либо другой поток прерывает текущий поток, и прерывание приостановки потока поддерживается;или происходит "ложное пробуждение".

Во всех случаях, прежде чем этот метод сможет вернуть текущий поток, необходимо повторно получить блокировку, связанную с этим условием.Когда поток возвращается, он гарантированно удерживает эту блокировку.

...