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

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

Поток 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, которые вообще не взаимодействуют с Thread 5.

0
Museus 3 Дек 2018 в 21:33

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- (Н-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
    }
}

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

0
mjkdr 5 Дек 2018 в 12:44