[英]How one thread can wait until another one finishes to fire some actions
如下面的代码所示,我在工作线程fileThread
上加载了一个繁重的文件,当该线程加载文件时,我创建了另一个线程fileLoadIndicator
来显示屏幕上的忙指示符。 我现在要做的是:在fileLoadIndicator
线程完成之后,我想启用一个按钮,但只有在fileLoadIndicator
线程完成之后。
我的尝试:
loadFile();// the very heavy file
/**
* The below thread "fileLoadIndicator"is to show busy indicator while our main file
that takes approx. 8 seconds to be loaded
*
*/
fileLoadIndicator = new Thread(fileLoadIndicatorRun);
fileLoadIndicator.start();
indicatorMonitor = new Thread(indicatorMonitorRun);
indicatorMonitor.start();
...
...
Runnable fileLoadIndicatorRun = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
statusarea.append(Log.w(TAG, "busyIndicatorRunnable", "Loading."));
StringBuilder sb = new StringBuilder(".");
do {
try {
fileThread.join(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sb.append(".");
statusarea.append(sb.toString());
} while (fileThread.getState() != State.TERMINATED);
//statusarea.append("/n");
}
};
Runnable indicatorMonitorRun = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
fileLoadIndicator.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setViewEnableState(Bpause, true);
}
};
但是在indicatorMonitorRun
发生的事情是, indicatorMonitor
线程等待整个方法loadFile()
,它逐行处理繁重的文件,整个过程可能需要70分钟,完成。 我只想在fileLoadIndicator
线程完成时启用一个按钮,我不应该等到整个文件加载和处理很长时间。
请告诉我我该怎么办。
我建议使用ExecutorService来管理线程池,如果你使用的是Java 8,请利用CompletableFuture,因为它简化了这些类型的任务,而不需要复杂的线程等待/通知和java.util.concurrency类型,例如:
package so.thread.wait;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class LongThreadWait {
public static void main(String[] args) throws Exception {
// thread pool for long running loaders
final ExecutorService fileLoaders = Executors.newCachedThreadPool();
// hook to be invoked when the file is done loading
final CompletableFuture<Long> completionFuture = new CompletableFuture<>();
completionFuture.thenAcceptAsync(LongThreadWait::completionConsumer);
fileLoaders.submit(new FileLoader(completionFuture));
Thread.sleep(TimeUnit.SECONDS.toMillis(3));
}
private static void completionConsumer(Long millis) {
System.out.println("Completed on Thread [" + Thread.currentThread().getName() + "] in " + millis + " ms");
}
private static class FileLoader implements Runnable {
private CompletableFuture<Long> completionFuture;
public FileLoader(CompletableFuture<Long> completionFuture) {
this.completionFuture = completionFuture;
}
@Override
public void run() {
long start = System.currentTimeMillis();
// load file for a long time
System.out.println("Loading file on Thread [" + Thread.currentThread().getName() + "]");
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(2));
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
// invoke the completion future with the elapsed milliseconds
completionFuture.complete(end - start);
}
}
}
默认情况下,CompletableFuture.thenAcceptAsync(..)在JVM的默认“ForkJoin”线程池中运行提供的钩子,有一个可选的第二个参数,您可以在其中提供自己的ExecutorService来定义执行完成钩子的线程。
这种类型的设置简化了线程管理和复杂的等待语义。
您还应注意,CompletableFuture具有全面的流畅API,可以简化线程结果的复杂链接。
考虑使用CountDownLatch 。 将其初始化为1.加载线程完成后,可以调用countDown 。 您的监视器线程可以轮询计数或只是等待完成。
您可以使用“ExecutorService”来创建线程池,然后监视线程并等待线程终止以启用该按钮。
class FileThreadThread implements Runnable {
public FileThreadThread() {
}
@Override
public void run() {
}
}
class FileLoadIndicatorRunThread implements Runnable {
private ExecutorService fileLoadIndicatorExecutor = null;
@Override
public void run() {
if (fileLoadIndicatorExecutor == null || fileLoadIndicatorExecutor.isShutdown()) {
fileLoadIndicatorExecutor = Executors.newCachedThreadPool(CustomizableThreadFactory.createSingleNamedFactory("FileLoaderThreadPool"));
}
for(int i=0; number_of_files; i++){
fileLoadIndicatorExecutor.execute(new FileThreadThread());
}
//Request executor shutdown after all threads are completed
fileLoadIndicatorExecutor.shutdown();
while (isRunning) {
boolean threadTerminated = fileLoadIndicatorExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
if(threadTerminated){
// enable a button
isRunning = false;
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.