【问题标题】:Java ArrayBlockingQueue take sourceJava ArrayBlockingQueue 取源码
【发布时间】:2018-11-08 19:16:29
【问题描述】:

我在阅读 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:等待(停车) 在 sun.misc.Unsafe.park(本机方法) - 停车等待 (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) 在 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.util.concurrent.ThreadPoolExecutor.runWorker(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:等待(停车) 在 sun.misc.Unsafe.park(本机方法) - 停车等待 (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) 在 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.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 在 java.lang.Thread.run(Thread.java:745)

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

【问题讨论】:

    标签: java multithreading concurrency locking


    【解决方案1】:

    只有一个线程可以同时持有ReentrantLock

    notEmptyCondition对象,当前线程调用Condition.await()时会释放锁:

    使当前线程等待,直到它发出信号或 打断了。与此条件关联的锁是原子的 释放 并且当前线程被禁用线程调度 目的并处于休眠状态,直到发生以下四种情况之一:

    • 其他一些线程为此条件调用 signal() 方法,并且 当前线程恰好被选为要被唤醒的线程;
    • 或其他一些线程为此调用 signalAll() 方法 条件;
    • 或其他线程中断当前线程,并且 支持线程挂起中断; - 或“虚假唤醒” 发生。

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

    【讨论】:

    • 您应该明确指出notEmpty 是绑定到lockCondition,因为这在问题中的代码中并不明显。
    • 谢谢。您指出 condition.await() 将释放锁,这是以前不知道的。有了这些知识,我就能明白问题出在哪里了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 2011-03-12
    • 1970-01-01
    • 2012-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多