阻止和唤醒消费者线程/

时间:2011-12-18 16:29:42

标签: java multithreading

我有2个帖子。

每个人都从共享缓冲区中读取一些数据。

currentDataBuffer.get(thisID); //currentDataBuffer is my shared buffer object

我想在每次调用get之后阻塞每个线程,并在所有线程读取缓冲区时释放它(一次) 所以我使用这个currentDataBuffer对象作为锁:

currentDataBuffer.get(thisID);
synchronized (currentDataBuffer ) {
   currentDataBuffer.wait();
}

问题是如何在所有线程完成从缓冲区读取(每行一行)后释放这些线程?

currentDataBuffer里面我有一个地图,我存储了从缓冲区读取数据的线程ID。

如何使用this.notifyAll();(来自currentDataBuffer)唤醒所有锁定的线程?

3 个答案:

答案 0 :(得分:0)

我建议你使用Java BlockingQueue数据结构。调用BlockingQueue.take()块直到元素可用。 所以而不是:

currentDataBuffer.get(thisID);
synchronized (currentDataBuffer ) {
   currentDataBuffer.wait();
}

你将拥有:

currentDataBuffer.take();

可以通过调用take()方法向队列添加元素来释放BlockingQueue.offer(object)调用中阻塞的线程

答案 1 :(得分:0)

继续使用代码的答案可能是使用currentDataBuffer.notifyAll()代替this.notifyAll()(不清楚this从您的问题中引用的内容)。但是,如果所有线程都已读取缓冲区并进入等待状态,您将如何确保调用notifyAll

如果您知道应该读取缓冲区的线程数,那么更好的解决方案是使用两个CountDownLatch。在该类的javadoc中有一个很好的例子。

------------更新:

您无需更改阅读器线程的代码。您应该在currentDataBuffer对象中保留锁存器。在currentDataBuffer中创建一个等待n项锁存的线程。在get方法中,在读取完成后在该锁存器上调用CountDownLatch.countDown()。哦,我会写的:

class CurrentDataBuffer implements Runnable {

    private CountDownLatch singleThreadFinishedSignal;
    private CountDownLatch allThreadsFinishedSignal;

    public CurrentDataBuffer(int N) {
        singleThreadFinishedSignal = new CountDownLatch(N); // waiter thread waits on this
        allThreadsFinishedSignal = new CountDownLatch(1); // reader threads wait on this after finished reading
    }

    public void run() {
        try {
            singleThreadFinishedSignal.await(); // wait for all reader threads to finish
            allThreadsFinishedSignal.countDown(); // let all reader threads proceed
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void get() {
        try {
            // read buffer item here ///////////////////
            singleThreadFinishedSignal.countDown(); // mark that a thread has read the item
            allThreadsFinishedSignal.await(); // wait for other reader threads to finish
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

答案 2 :(得分:0)

我认为CountdownLatch(http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.html)会有所帮助。

即。使用初始值为2的CountDownLatch(或您想要处理的任意数量的线程)来扩充currentDataBuffer。处理完线程后,调用latch.countDown()然后调用latch.await()。

为了安全起见,您可能要小心countDowns不会丢失(例如,如果抛出异常)。