Вопрос синхронизации потоков (в Java) - PullRequest
4 голосов
/ 08 октября 2008

У моего java-приложения есть задача загрузки, которая требует двух обращений к серверу, которые могут быть распараллелены. Поэтому я запускаю поток t1 (выполняющий task1 ) и поток t2 (для task2 ). Затем я хочу выполнить определенную задачу, task3 , когда обе другие задачи (1 и 2) закончены. Естественно, я не могу сказать, какой из task1 и task2 закончится первым ...

Какой для вас самый простой (и самый безопасный) способ закодировать это?

Спасибо за вашу помощь

Ответы [ 4 ]

7 голосов
/ 08 октября 2008

У вас есть несколько вариантов:

  1. Если задача 3 находится в отдельном потоке, а потоки задачи 1 и задачи 2 являются исключительными для своих задач (без объединения потоков) и завершают работу после завершения задачи, вы можете использовать {T1.join (); T2.join ();} ждать обоих потоков. Плюсы: легко. Минусы: Ситуация редко бывает такой простой.
  2. Если task3 находится в отдельном потоке, вы можете использовать java.util.concurrent.CountDownLatch, общий для всех потоков. Задача 3 будет ждать защелки, а задачи 1 и 2 уменьшат ее. Плюсы: довольно легко, не обращая внимания на окружающую среду. Минусы: требуется создать T3, прежде чем он действительно понадобится.
  3. Если задача 3 должна создаваться только ПОСЛЕ выполнения задачи 1 и задачи 2 (для нее нет отдельного потока, пока не завершатся задачи 1 и 2), вам придется создать что-то более сложное. Я бы порекомендовал либо создать свой собственный ExecutorService, который принимает условие и дополнение к будущему и выполняет будущее только при изменении условия, либо создать службу управления, которая будет проверять условия и отправлять данные фьючерсы на основе этих условий. Имейте в виду, это из головы, могут быть более простые решения. Плюсы: ресурсосберегающий. Минусы: сложные.
2 голосов
/ 08 октября 2008

Вы можете join и t1 и t2 (в любом порядке), а затем запустить задачу 3 после объединения.

0 голосов
/ 08 октября 2008

Если вы не хотите прерывать 2 рабочих потока (task1 и task2), когда они завершат свою работу, тогда вы можете подождать условие в task3, пока два других не завершат работу. Примерно так:

public class Master {

    private Object monitor_ = new Object();
    private boolean task1Finished_;
    private boolean task2Finished_;

    class Task1 extends Thread {

        public void run() {
            // do stuff
            synchronized (monitor_) {
                task1Finished_ = true;
                monitor_.notifyAll();
            }
            // keep on working
        }
    }

    class Task2 extends Thread {

        public void run() {
            // do stuff
            synchronized (monitor_) {
                task1Finished_ = true;
                monitor_.notifyAll();
            }
            // keep on working
        }
    }

    class Task3 extends Thread {

        public void run() {
            synchronized (monitor_) {
                while (!task1Finished_ || !task2Finished_) {
                    try {
                        monitor_.wait();
                    }
                    catch (InterruptedException ignored) {
                    }
                }
            }
            // do stuff
        }
    }
    // start tasks1, task2 and task3...
}
0 голосов
/ 08 октября 2008

Внедрите интерфейс слушателя в свою задачу 3 и зарегистрируйте его как для задачи 1, так и для задачи 2. Task1 и Task2 должны будут вызвать своего слушателя перед завершением. При этом вы можете записать в задании 3, какое задание уже выполнено, а когда оба завершены, вы можете выполнить свое третье задание.

Конечно, если одно из ваших заданий 1/2 может завершиться с исключением, не забудьте указать задание 3 как UncaughtExceptionHandler

...