Java Ожидание завершения потока - PullRequest
49 голосов
/ 14 января 2011

У меня есть нить, загружающая данные, и я хочу дождаться окончания загрузки, прежде чем загружать данные. Есть ли стандартный способ сделать это?

Подробнее:

У меня есть класс Download, который получает данные из URL-адреса (Сериализованные POJO). Скачать можно запустить и наблюдать. Он отслеживает загруженные байты и размер загрузки. У меня есть индикатор выполнения, который отображает прогресс для пользователя. GUI наблюдает за Download, чтобы обновить индикатор выполнения.

Когда POJO загружен, я хочу получить его и перейти к следующему шагу. Каждый шаг должен ждать завершения предыдущего. Проблема в том, что я не могу придумать, как приостановить приложение и дождаться загрузки. Как только загрузка закончится, я хочу вызвать download.getObject (), который вернет данные в виде объекта. Затем я могу разыграть его и приступить к следующей загрузке.

У меня есть вспомогательный класс, который управляет URL-адресами для загрузки и выполняет все вызовы для загрузки. Этот вызов вызовет getObject и выполнит приведение. Gui вызывает helper.getUser (). helper запускает поток, и я хочу, чтобы он «знал», когда он закончил, чтобы он мог вернуть приведенный объект.

Есть предложения / примеры? Я нахожусь в начальной стадии этого дизайна, поэтому я хочу изменить его.

Спасибо, любезно.

Обновление:

Я следовал http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html#get и использовал модал для блокировки до завершения потока. Код был очень грязным, и мне не нравится такой подход. Я буду продолжать пытаться найти «чистый» способ обработки рабочего процесса загрузки.

Ответы [ 9 ]

66 голосов
/ 14 января 2011

Thread имеет метод, который делает это для вас join , который будет блокироваться, пока поток не завершит выполнение.

49 голосов
/ 20 декабря 2011

Вы можете использовать CountDownLatch из пакета java.util.concurrent. Это очень полезно при ожидании завершения одного или нескольких потоков перед продолжением выполнения в ожидающем потоке.

Например, ожидание выполнения трех задач:

CountDownLatch latch = new CountDownLatch(3);
...
latch.await(); // Wait for countdown

Затем каждый другой поток (ы) вызывает latch.countDown(), когда завершает свои задачи. После завершения обратного отсчета три в этом примере выполнение будет продолжено.

13 голосов
/ 14 января 2011

SwingWorker имеет doInBackground(), который можно использовать для выполнения задачи. У вас есть возможность вызвать get() и дождаться завершения загрузки, или вы можете переопределить метод done(), который будет вызываться в потоке диспетчеризации событий после завершения SwingWorker.

Swingworker имеет преимущества перед вашим текущим подходом в том, что он обладает многими функциями, которые вы ищете, поэтому нет необходимости заново изобретать колесо. Вы можете использовать методы getProgress() и setProgress() в качестве альтернативы наблюдателю в исполняемом файле для прогресса загрузки. Метод done(), как я указывал выше, вызывается после того, как рабочий завершает выполнение и выполняется в EDT, это позволяет загружать данные после завершения загрузки.

7 голосов
/ 13 сентября 2016

Более совершенные альтернативы метод join () развивались в течение определенного периода времени.

ExecutorService.html # invokeAll является одной из альтернатив.

Выполняет заданные задачи, возвращая список Фьючерсов с их статусом и результатами, когда все выполнено. Future.isDone () имеет значение true для каждого элемента возвращаемого списка.

Обратите внимание, что завершенная задача могла быть завершена либо нормально, либо с помощью исключения. Результаты этого метода не определены, если данная коллекция была изменена во время выполнения этой операции.

ForkJoinPool или Executors.html # newWorkStealingPool предоставляет другие альтернативы для достижения той же цели.

Пример кода:

import java.util.concurrent.*;

import java.util.*;

public class InvokeAllDemo{
    public InvokeAllDemo(){
        System.out.println("creating service");
        ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

        List<MyCallable> futureList = new ArrayList<MyCallable>();
        for ( int i=0; i<10; i++){
            MyCallable myCallable = new MyCallable((long)i);
            futureList.add(myCallable);
        }
        System.out.println("Start");
        try{
            List<Future<Long>> futures = service.invokeAll(futureList);  
        }catch(Exception err){
            err.printStackTrace();
        }
        System.out.println("Completed");
        service.shutdown();
    }
    public static void main(String args[]){
        InvokeAllDemo demo = new InvokeAllDemo();
    }
    class MyCallable implements Callable<Long>{
        Long id = 0L;
        public MyCallable(Long val){
            this.id = val;
        }
        public Long call(){
            // Add your business logic
            return id;
        }
    }
}
4 голосов
/ 14 января 2011

Я полагаю, что вы вызываете свою загрузку в фоновом потоке, например, предоставляемом SwingWorker. Если это так, просто вызовите следующий код последовательно в том же методе doInBackground SwingWorker.

3 голосов
/ 26 апреля 2017

Вы можете использовать join(), чтобы дождаться завершения всех потоков. Сохраняйте все объекты потоков в глобальном ArrayList во время создания потоков. После этого держите его в цикле, как показано ниже:

for (int i = 0; i < 10; i++) 
{
    Thread T1 = new Thread(new ThreadTest(i));                
    T1.start();                
    arrThreads.add(T1);
} 

for (int i = 0; i < arrThreads.size(); i++) 
{
    arrThreads.get(i).join(); 
}

Проверьте здесь для получения полной информации: http://www.letmeknows.com/2017/04/24/wait-for-threads-to-finish-java

3 голосов
/ 14 января 2011

Обычно, когда вы хотите дождаться завершения потока, вы должны вызвать join () для него.

1 голос
/ 14 января 2011

Есть предложения / примеры? Я следовал SwingWorker ... Код был очень грязным, и мне не нравится этот подход.

Вместо get(), ожидающего завершения, используйте process() и setProgress() для отображения промежуточных результатов, как предлагается в этом простом примере или в этом связанном примере

0 голосов
/ 02 сентября 2016

Метод join () позволяет одному потоку ожидать завершения другого. Однако, как и в случае сна, соединение зависит от ОС для синхронизации, поэтому не следует предполагать, что соединение будет ожидать именноесли вы укажете.

...