Как сделать так, чтобы Тема просыпалась последней при уведомлении?

У меня есть несколько потоков, ожидающих уведомления () от тиковых часов. Один из этих потоков должен дождаться выполнения остальных, прежде чем он запустится. Обычно я считаю, что способ сделать это - использовать join(), но в этом случае потоки никогда не умирают, они просто ждут () следующего тикового сигнала. Есть ли способ обеспечить, чтобы поток "z" всегда просыпался после потока "ay" при получении одного и того же уведомления ()?

РЕДАКТИРОВАТЬ: добавлен код, например

Тема 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 ответ

Решение

Если я правильно понимаю, есть N задач, которые нужно выполнить, когда подается тиковый сигнал. N-я задача может начаться только после того, как первые N-1 задачи будут выполнены. Поскольку функция notifyAll() уведомляет потоки неупорядоченным образом, вам необходимо немного расширить свой код.

Прежде всего, я думаю, что эта конструкция не является безопасной конструкцией. Подумайте о том, что выполнение кода в потоке занимает больше 1 секунды. В этом случае поток не будет уведомлен при следующем сигнале тика, так как он еще не достиг функции wait(). Однако давайте пока предположим, что этого не произойдет.

Так как N-я задача может быть выполнена только после того, как первые N-1 задачи выполнены, она должна ждать и должна быть уведомлена, когда первые 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
    }
}

Как я уже указывал, эта конструкция потерпит неудачу, если время выполнения в потоке будет больше, чем время между двумя тиками. Пожалуйста, дайте мне точно знать, в чем проблема, чтобы дать вам более подходящий ответ.

Другие вопросы по тегам