等待线程完成

我有一个线程下载数据,我想等待,直到下载完成之前,我加载的数据。有什么标准的方法吗?

更多信息:

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

当下载 POJO 时,我希望获得它并进入下一步。每一步都要等到前一步完成。问题是我想不出一种方法来暂停我的应用程序,等待下载线程。一旦下载完成,我想调用 download.getObject(),它将返回的数据作为一个对象。然后我就可以施放它,并继续下一个下载。

我有一个 helper 类,它管理要下载的 URL,并调用所有要下载的 URL。这个调用将调用 getObject 并执行强制转换。鬼叫 helper.getUser()。助手启动线程运行,我希望它知道什么时候结束,这样它就可以返回强制转换的对象。

有什么建议或例子吗? 我在这个设计的初期阶段,所以我愿意改变它。

更新:

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

250005 次浏览

Thread has a method that does that for you join which will block until the thread has finished executing.

Generally, when you want to wait for a thread to finish, you should call join() on it.

I imagine that you're calling your download in a background thread such as provided by a SwingWorker. If so, then simply call your next code sequentially in the same SwingWorker's doInBackground method.

SwingWorker has doInBackground() which you can use to perform a task. You have the option to invoke get() and wait for the download to complete or you can override the done() method which will be invoked on the event dispatch thread once the SwingWorker completes.

The Swingworker has advantages to your current approach in that it has many of the features you are looking for so there is no need to reinvent the wheel. You are able to use the getProgress() and setProgress() methods as an alternative to an observer on the runnable for download progress. The done() method as I stated above is called after the worker finishes executing and is performed on the EDT, this allows you load the data after the download has completed.

Any suggestions/examples? I followed SwingWorker... The code was very messy and I don't like this approach.

Instead of get(), which waits for completion, use process() and setProgress() to show intermediate results, as suggested in this simple example or this related example.

You could use a CountDownLatch from the java.util.concurrent package. It is very useful when waiting for one or more threads to complete before continuing execution in the awaiting thread.

For example, waiting for three tasks to complete:

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

The other thread(s) then each call latch.countDown() when complete with the their tasks. Once the countdown is complete, three in this example, the execution will continue.

The join() method allows one thread to wait for the completion of another.However, as with sleep, join is dependent on the OS for timing, so you should not assume that join will wait exactly as long as you specify.

Better alternatives to join() method have been evolved over a period of time.

ExecutorService.html#invokeAll is one alternative.

Executes the given tasks, returning a list of Futures holding their status and results when all complete. Future.isDone() is true for each element of the returned list.

Note that a completed task could have terminated either normally or by throwing an exception. The results of this method are undefined if the given collection is modified while this operation is in progress.

ForkJoinPool or Executors.html#newWorkStealingPool provides other alternatives to achieve the same purpose.

Example code snippet:

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

You can use join() to wait for all threads to finish. Like below:

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