Как сделать так, чтобы Тема просыпалась последней при уведомлении? - PullRequest
0 голосов
/ 03 декабря 2018

У меня есть несколько потоков, ожидающих уведомления () от тиковых часов.Один из этих потоков должен дождаться выполнения остальных, прежде чем он запустится.Обычно я считаю, что способ сделать это - использовать 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 Ответ

0 голосов
/ 05 декабря 2018

Если я правильно понимаю, есть 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
    }
}

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

...