简体   繁体   English

Java 等待线程完成

[英]Java Wait for thread to finish

I have a thread downloading data and I want to wait until the download is finished before I load the data.我有一个线程正在下载数据,我想等到下载完成后再加载数据。 Is there a standard way of doing this?有这样做的标准方法吗?

More Info:更多信息:

I have a Download class that gets data from a URL (Serialized POJOs).我有一个从 URL(序列化 POJO)获取数据的下载类。 Download is Runnable and Observable.下载是可运行和可观察的。 It keeps track of the bytes downloaded and download size.它跟踪下载的字节数和下载大小。 I have a progress bar that displays the progress to the User.我有一个向用户显示进度的进度条。 The GUI observes Download to update the progress bar. GUI 观察下载以更新进度条。

When the POJO is downloaded I want to get it and move to the next step.下载 POJO 后,我想获取它并转到下一步。 Each step has to wait for the previous to finish.每一步都必须等待上一步完成。 The problem is I cant think of a way to pause my application to wait for the download thread.问题是我想不出一种方法来暂停我的应用程序以等待下载线程。 Once the download is finished I want to call download.getObject() which will return the data as an object.下载完成后,我想调用download.getObject() ,它将数据作为对象返回。 I can then cast it and get on with the next download.然后我可以投射它并继续下一次下载。

I have a helper class that manages the URLs for download and makes all of the calls to Download.我有一个帮助类来管理下载的 URL 并进行所有对下载的调用。 This call will call getObject and do the casting.此调用将调用 getObject 并进行强制转换。 The Gui calls helper.getUser() . Gui 调用helper.getUser() helper starts the thread running and I want it to 'know' when it is finished so it can return the casted object. helper 启动线程运行,我希望它“知道”它何时完成,以便它可以返回强制转换的对象。

Any suggestions/examples?有什么建议/例子吗? I am in the beginning stages of this design so I am willing to change it.我正处于这个设计的开始阶段,所以我愿意改变它。

Update:更新:

I followed http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html#get and used modal to block until the thread finished.我跟着http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html#get并使用模态阻塞直到线程完成。 The code was very messy and I don't like this approach.代码非常混乱,我不喜欢这种方法。 I will keep trying to find a 'clean' way to handle the workflow of the download processes.我将继续努力寻找一种“干净”的方式来处理下载过程的工作流程。

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

You could use a CountDownLatch from the java.util.concurrent package.您可以使用java.util.concurrent包中的CountDownLatch 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.然后,其他线程在完成任务时分别调用latch.countDown() Once the countdown is complete, three in this example, the execution will continue.一旦倒计时完成,在这个例子中是三个,执行将继续。

Better alternatives to join() method have been evolved over a period of time. join()方法的更好替代方案已经发展了一段时间。

ExecutorService.html#invokeAll is one alternative. ExecutorService.html#invokeAll是一种选择。

Executes the given tasks, returning a list of Futures holding their status and results when all complete.执行给定的任务,返回一个 Futures 列表,在所有完成时保存它们的状态和结果。 Future.isDone() is true for each element of the returned list. Future.isDone() 对于返回列表的每个元素都是 true。

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. ForkJoinPoolExecutors.html#newWorkStealingPool提供了其他替代方案来实现相同的目的。

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.您可以使用join()等待所有线程完成。 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();
    }
}

SwingWorker has doInBackground() which you can use to perform a task. SwingWorker具有doInBackground() ,您可以使用它来执行任务。 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.您可以选择调用get()并等待下载完成,或者您可以覆盖done()方法,一旦 SwingWorker 完成,该方法将在事件调度线程上调用。

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. Swingworker 与您当前的方法相比具有优势,因为它具有您正在寻找的许多功能,因此无需重新发明轮子。 You are able to use the getProgress() and setProgress() methods as an alternative to an observer on the runnable for download progress.您可以使用getProgress()setProgress()方法作为可运行对象上的观察者的替代方法来获取下载进度。 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.我上面提到的done()方法在 worker 完成执行后调用,并在 EDT 上执行,这允许您在下载完成后加载数据。

I imagine that you're calling your download in a background thread such as provided by a SwingWorker.我想您正在后台线程中调用您的下载,例如 SwingWorker 提供的。 If so, then simply call your next code sequentially in the same SwingWorker's doInBackground method.如果是这样,那么只需在同一个 SwingWorker 的 doInBackground 方法中按顺序调用您的下一个代码。

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

Any suggestions/examples?有什么建议/例子吗? I followed SwingWorker ... The code was very messy and I don't like this approach.我跟着SwingWorker ......代码很乱,我不喜欢这种方法。

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

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

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

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