我如何使线程最后一次在通知时唤醒?

时间:2018-12-03 18:33:55

标签: java multithreading concurrency wait notify

我有多个线程正在等待滴答时钟发出的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交互。

1 个答案:

答案 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
    }
}

正如我已经指出的,如果一个线程中的执行时间大于两次滴答之间的时间,则这种构造将失败。请让我确切知道问题所在,以便为您提供更合适的答案。