Подтвердить что ты не робот

Java Подождите, пока поток завершится

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

Дополнительная информация:

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

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

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

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

Благодарим вас.

Update:

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

Ответ 3

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

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

Ответ 4

Лучшие альтернативы методу 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;
        }
    }
}

Ответ 5

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

Ответ 6

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

Ответ 7

Вы можете использовать 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

Ответ 8

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

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

Ответ 9

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