我有多个线程正在等待滴答时钟发出的notify()。这些线程之一应在运行之前等待其余线程执行。通常,我相信这样做的方法是使用join(),但是在这种情况下,线程永不消亡,它们只是等待下一个滴答信号。有没有办法确保在收到相同的notify()之后,线程“ z”将始终在线程“ a-y”之后唤醒?
编辑:添加了示例代码
线程1-4:
while(running) {
synchronized(tickSignal){
/*
* Code in this section adds objects to a queue that Thread 5 reads
* It also has other code that must be executed every tick
*/
tickSignal.wait();
}
}
线程5:
while(running) {
synchronized(tickSignal) {
/*
* Code in this section reads all the objects added to the queue by T1-4
* It also has other code that must be executed every tick
*/
tickSignal.wait();
}
}
刻度时钟:
while(running) {
synchronized(tickSignal){
tickSignal.notifyAll();
}
Thread.sleep(1000);
}
还有其他监视tickSignal的线程根本不与线程5交互。
答案 0 :(得分:0)
如果我理解正确,则在发出滴答信号时有 N 个任务要执行。第 N 个任务只能在第一个 N-1 个任务完成后开始。由于notifyAll()函数以无序方式通知线程,因此您必须稍微扩展代码。
首先,我认为此结构不是安全的结构。考虑一下在一个线程中执行代码花费超过1秒的情况。在这种情况下,由于线程尚未到达wait()函数,因此不会在下一个滴答信号处通知该线程。但是,现在让我们假设这不会发生。
由于第 N 个任务只能在第一个 N-1 个任务完成后才能执行,因此它必须等待并在第一个 em> N-1 个任务实际上已经完成。 为了计算已完成任务的数量,可以使用线程安全的AtomicInteger计数器。每次任务完成时,计数器都会增加1。当计数器达到值 N-1 时,它会通知 N 个线程并将其值重置为0。
为您提供代码:
// Besides a tickSignal, we also need a finalThreadSignal, which
// will be notified when the first N-1 Threads are finished.
private Object tickSignal = new Object();
private Object finalThreadSignal = new Object();
private AtomicInteger completedThreadsCounter = new AtomicInteger(0);
线程1-(N-1):
while (running) {
synchronized (tickSignal) {
try {
tickSignal.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Code
// Task finished
int counter = completedThreadsCounter.incrementAndGet();
if (counter == N-1) {
// Notify Thread N when the first N-1 tasks are finished
synchronized (finalThreadSignal) {
finalThreadSignal.notify();
}
// Reset the finished Threads counter and wait for the next tick signal
completedThreadsCounter.set(0);
}
}
}
线程N:
while (running) {
// Here we synchronize on the signal that will be given when
// the first N-1 Threads are finished
synchronized (finalThreadSignal) {
try {
finalThreadSignal.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Execute final Thread code
}
}
正如我已经指出的,如果一个线程中的执行时间大于两次滴答之间的时间,则这种构造将失败。请让我确切知道问题所在,以便为您提供更合适的答案。