我有2个帖子。
每个人都从共享缓冲区中读取一些数据。
currentDataBuffer.get(thisID); //currentDataBuffer is my shared buffer object
我想在每次调用get之后阻塞每个线程,并在所有线程读取缓冲区时释放它(一次)
所以我使用这个currentDataBuffer
对象作为锁:
currentDataBuffer.get(thisID);
synchronized (currentDataBuffer ) {
currentDataBuffer.wait();
}
问题是如何在所有线程完成从缓冲区读取(每行一行)后释放这些线程?
在currentDataBuffer
里面我有一个地图,我存储了从缓冲区读取数据的线程ID。
如何使用this.notifyAll();
(来自currentDataBuffer
)唤醒所有锁定的线程?
答案 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不会丢失(例如,如果抛出异常)。