【问题标题】:Java Blocking Queue Implementation QuestionsJava阻塞队列实现问题
【发布时间】:2015-04-09 15:12:05
【问题描述】:

常见的实现是here,Java的内置实现是here。关于这两种实现,我有两个问题:

1) 第一个实现在 put() 和 take() 方法上使用synchronized 关键字,这意味着只有一个线程可以访问一个方法。假设线程A调用put()发现队列已满,等待,那么由于锁还没有释放,没有人可以调用take()方法,怎么实现呢?

2) Java 的内置使用了两个锁:takeLock 和 putLock,分别用于 put() 和 take()。我看到区间队列是一个链表,不是线程安全的,怎么办?

【问题讨论】:

  • for 1:等待释放锁,所以不会阻塞其他线程占用。
  • 您在#1 中的假设是错误的:调用wait() 实际上释放了该线程的锁。然后另一个线程可以在take()方法中捕获锁,当notifyAll()被另一个线程调用时,卡在put()中的线程将被唤醒。
  • @NathanHughes 感谢您的澄清
  • @PlatinumAzure 谢谢,第二个有什么想法吗?

标签: java multithreading blockingqueue


【解决方案1】:

正如在一些 cmets 中已经提到的,第一个实现只是使用传统的 wait()/notify() 机制,其中一个线程等待(当然还有释放锁)以获得其他线程的通知。

第二个使用不同的锁进行 put 和 take 操作。因此各个操作(同时 put() 或 take())是同步的。但是当队列已满或为空时,它们需要相互通信。所以他们通过condition相互交流。签出两个私有方法-

    /**
     * Signals a waiting take. Called only from put/offer (which do not
     * otherwise ordinarily lock takeLock.)
     */
    private void signalNotEmpty() {
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lock();
        try {
            notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
    }

    /**
     * Signals a waiting put. Called only from take/poll.
     */
    private void signalNotFull() {
        final ReentrantLock putLock = this.putLock;
        putLock.lock();
        try {
            notFull.signal();
        } finally {
            putLock.unlock();
        }
    }

put 方法通知其他线程尝试从空队列中获取/轮询,take 方法通知其他线程尝试将元素放入完整队列。

【讨论】:

  • 谢谢,我试图了解两个锁如何保证线程安全,仔细检查代码,发现 put/take 操作是在两个节点(分别为头/尾)上执行的,这解释了一切。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-05
  • 2015-07-05
  • 2014-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多