繁体   English   中英

Java 等待线程完成

[英]Java Wait for thread to finish

我有一个线程正在下载数据,我想等到下载完成后再加载数据。 有这样做的标准方法吗?

更多信息:

我有一个从 URL(序列化 POJO)获取数据的下载类。 下载是可运行和可观察的。 它跟踪下载的字节数和下载大小。 我有一个向用户显示进度的进度条。 GUI 观察下载以更新进度条。

下载 POJO 后,我想获取它并转到下一步。 每一步都必须等待上一步完成。 问题是我想不出一种方法来暂停我的应用程序以等待下载线程。 下载完成后,我想调用download.getObject() ,它将数据作为对象返回。 然后我可以投射它并继续下一次下载。

我有一个帮助类来管理下载的 URL 并进行所有对下载的调用。 此调用将调用 getObject 并进行强制转换。 Gui 调用helper.getUser() helper 启动线程运行,我希望它“知道”它何时完成,以便它可以返回强制转换的对象。

有什么建议/例子吗? 我正处于这个设计的开始阶段,所以我愿意改变它。

更新:

我跟着http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html#get并使用模态阻塞直到线程完成。 代码非常混乱,我不喜欢这种方法。 我将继续努力寻找一种“干净”的方式来处理下载过程的工作流程。

Thread有一个方法可以为您加入,该方法将阻塞,直到线程完成执行。

您可以使用java.util.concurrent包中的CountDownLatch 在等待一个或多个线程完成后再在等待线程中继续执行时非常有用。

例如,等待三个任务完成:

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

然后,其他线程在完成任务时分别调用latch.countDown() 一旦倒计时完成,在这个例子中是三个,执行将继续。

join()方法的更好替代方案已经发展了一段时间。

ExecutorService.html#invokeAll是一种选择。

执行给定的任务,返回一个 Futures 列表,在所有完成时保存它们的状态和结果。 Future.isDone() 对于返回列表的每个元素都是 true。

请注意,已完成的任务可能已经正常终止,也可能通过引发异常终止。 如果在此操作进行时修改了给定的集合,则此方法的结果是不确定的。

ForkJoinPoolExecutors.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;
        }
    }
}

您可以使用join()等待所有线程完成。 如下所示:

for (int i = 0; i < 10; i++) 
{
    Thread T1 = new Thread(new ThreadTest(i));                
    T1.start();   
    try {             
       T1.join(); 
    } catch (InterruptedException e) {
       e.printStackTrace();
    }
}

SwingWorker具有doInBackground() ,您可以使用它来执行任务。 您可以选择调用get()并等待下载完成,或者您可以覆盖done()方法,一旦 SwingWorker 完成,该方法将在事件调度线程上调用。

Swingworker 与您当前的方法相比具有优势,因为它具有您正在寻找的许多功能,因此无需重新发明轮子。 您可以使用getProgress()setProgress()方法作为可运行对象上的观察者的替代方法来获取下载进度。 我上面提到的done()方法在 worker 完成执行后调用,并在 EDT 上执行,这允许您在下载完成后加载数据。

我想您正在后台线程中调用您的下载,例如 SwingWorker 提供的。 如果是这样,那么只需在同一个 SwingWorker 的 doInBackground 方法中按顺序调用您的下一个代码。

一般来说,当你想等待一个线程完成时,你应该在它上面调用join()

有什么建议/例子吗? 我跟着SwingWorker ......代码很乱,我不喜欢这种方法。

代替等待完成的get() ,使用process()setProgress()来显示中间结果,如这个简单示例或这个相关示例中所建议的那样。

join()方法允许一个线程等待另一个线程完成。但是,与 sleep 一样,join 的时间取决于操作系统,因此您不应假设 join 将完全等待您指定的时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM