Java等待线程完成

问题描述:

我有一个线程下载数据,我想等到下载完成后才加载数据。有没有这样做的标准方式?Java等待线程完成

更多信息:

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

当POJO下载时,我想获取它并转到下一步。每一步都要等待前一个结束。问题是我不能想办法暂停我的应用程序来等待下载线程。一旦下载完成,我想调用download.getObject(),它将把数据作为一个对象返回。然后我可以投下它并继续下一次下载。

我有一个帮助类,管理下载的URL并使所有的下载调用。这个调用将调用getObject并执行转换。 Gui调用helper.getUser()。助手启动线程运行,并且我希望它在完成时“知道”,以便它可以返回铸造的对象。

任何建议/示例?我处于这个设计的开始阶段,所以我愿意改变它。

谢谢。

更新:

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

Thread有一个方法可以帮你。 join将阻塞,直到线程完成执行。

+0

我想加盟(),但保留了GUI的更新。我使用线程的原因是在下载过程中保持GUI更新。调用加入停止发生。 – Allan 2011-01-14 13:41:19

+4

join()将起作用。如果GUI停止更新,则可能必须更详细地说明要加入的线程。我不会加入美国东部时间。 – akf 2011-01-14 13:49:59

+2

然后你需要确保你没有在swing线程中调用`join()`。你可以通过创建一个负责你的下载线程的线程来做到这一点。这基本上只是一个你可以忘记的背景工作者。工作线程知道何时下载完成以及该做什么。你只需要确保摆动对象的编辑是在摆动线程中完成的。 – unholysampler 2011-01-14 13:50:36

通常,当你想等待一个线程完成时,你应该打电话给join()

我想象你在后台线程中调用你的下载,例如由SwingWorker提供。如果是这样,那么只需在同一个SwingWorker的doInBackground方法中依次调用您的下一个代码即可。

SwingWorkerdoInBackground()您可以使用它来执行任务。您可以选择预制get()并等待下载完成,或者您可以覆盖done()方法,一旦Swingworker完成,该方法将在事件分派线程上执行。

Swingworker具有您当前的方法的优点,因为它具有许多您正在寻找的功能,所以不需要重新发明*。您可以使用getProgress() & setProgress()方法作为可运行下载进度的观察者的替代方法。如上所述,done()方法在worker完成执行后调用,并在EDT上执行,这允许您在下载完成后加载数据。

任何建议/示例?我跟着SwingWorker ...代码非常混乱,我不喜欢这种方法。

代替get(),它等待完成,使用process()setProgress()显示中间结果,如以下简单example或该相关example建议。

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

例如,等了三个任务来完成:

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

另一个线程(或多个),然后每次调用latch.countDown()当与他们的任务完成了。一旦倒数完成,在这个例子中三个,执行将继续。

join()方法允许一个线程等待另一个线程的完成。但是,与睡眠一样,连接依赖于操作系统进行计时,因此您不应该认为连接将按照您指定的时间完全等待。

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

ExecutorService.html#invokeAll是一种选择。

执行给定的任务,返回持有其状态和结果的期货清单,当所有完成。 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();     
    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