在Java线程中,您可以在列表中包含一些线程,启动它们,然后使用主线程join
,然后执行另一个线程,等待所有进程完成后再继续。
在其他模型中,我不确定你会怎么做。以RootTools 3.0 Command类为例。你创建了一个Command
,有三种方法,commandOutput
,commandFinished
,commandTerminated
,虽然你可以使用回调在进程结束时做一些事情,但我不知道你将如何等待多个进程(例如,通过列出几个目录并总结文件大小)。
我相信Android Asynctask会有类似的问题 - 你可以很容易地进行回调,但没有办法等待几个任务。除非我错过了什么?
您可以在正在执行的命令上调用wait()。
虽然在执行此操作之前,您应该关闭您调用wait的命令的处理程序。您可以通过将RootTools.handlerEnabled设置为false或在每个单独的命令中使用构造函数并传入false来禁用该命令的处理程序来为每个命令执行此操作。
这很重要,因为如果使用了处理程序,那么它将尝试在您调用wait()的线程上调用回调方法,这将导致死锁。
当您为命令关闭处理程序并调用wait()时,该命令将在完成后调用notifyAll(),以便您的线程将恢复。
这方面的负面影响是,回调方法将不再在您正在处理的线程中完成,因此除非您实现处理程序或其他一些可接受的解决方案,否则您将无法使用这些回调方法执行任何UI工作。有了这个。
我之前的一个项目已经完成了这个主题,并找到了解决问题的不同解决方案(我最终使用方法1进行项目,因为它是该项目最适合的项目)。我将尽可能简单地与您分享。为了更好地理解,我将使用下载多个图像的示例来解释它们。
让ImageDownloader
成为一个从URL异步下载图像的类,它具有以下属性。
ImageDownloadCallback
在任务完成时获取回调。它有两种方法
void onSuccess(String imagePath)
:在任务成功完成时调用。
void onFailure()
:在任务未能完成时调用。download(String url, ImageDownloadCallback callback)
开始下载任务PauseModeCallbackHandler
,ChainModeCallbackHandler
和ParallelModeCallbackHandler
分别是这三种方法的回调的包装类。您可以根据要执行的任务来自定义它们。
通过暂停启动程序线程逐个执行任务。
优点 获取原始线程中的结果
缺点 需要让线程等待
您可以使用此类使线程等待,直到获得结果。
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Ahamad Anees P.A
* @version 1.0
* @param <T> type
*/
public class ThreadLockedTask<T> {
private AtomicReference<ResultWrapper<T>> mReference;
public ThreadLockedTask() {
mReference = new AtomicReference<>(new ResultWrapper<T>());
}
public T execute(Runnable runnable) {
runnable.run();
if (!mReference.get().mIsSet)
lockUntilSet();
return mReference.get().mResult;
}
private void lockUntilSet() {
synchronized (this) {
while (!mReference.get().isSet()) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public void setResult(T result) {
synchronized (this) {
ResultWrapper<T> wrapper = mReference.get();
wrapper.setResult(result);
wrapper.setIsSet(true);
notify();
}
}
public static class ResultWrapper<T> {
private boolean mIsSet;
private T mResult;
public boolean isSet() {
return mIsSet;
}
public T getResult() {
return mResult;
}
void setIsSet(boolean isCompleted) {
this.mIsSet = isCompleted;
}
void setResult(T result) {
this.mResult = result;
}
}
}
import java.util.ArrayList;
import java.util.List;
public class PauseModeCallbackHandler {
// List of results
private static List<String> results;
public static void start(final List<String> urls, final ImageDownloader.ProgressUpdateListener listener) {
new Thread(new Runnable() {
@Override
public void run() {
results = new ArrayList<>();
// Do tasks one by one
for (final String url :
urls) {
//Here the result is a String. Change "String" in the following two lines for other datatypes.
final ThreadLockedTask<String> task = new ThreadLockedTask<>();
final String imagePath = task.execute(new Runnable() {
@Override
public void run() {
//Start the task here
ImageDownloader.getInstance(listener).download(url,
new ImageDownloader.ImageDownloadCallback() {
@Override
public void onSuccess(String imagePath) {
//Set the result on success
task.setResult(imagePath);
}
@Override
public void onFailure() {
//Set result as null on failure
task.setResult(null);
}
});
}
});
if (imagePath!=null)
results.add(imagePath);
}
afterCallbacks();
}
}).start();
}
private PauseModeCallbackHandler() {}
private static void afterCallbacks() {
// All tasks completed. List "results" now holds the result
DemoActivity.isTasksInProgress = false;
}
}
从前一个回调中执行任务,就像连锁反应一样。
import java.util.ArrayList;
import java.util.List;
public class ChainModeCallbackHandler implements ImageDownloader.ImageDownloadCallback {
// List of args to start the task. Use pojo classes if your task has multiple args
private static List<String> urls;
// List of results
private static List<String> results;
// Optional.
private static ImageDownloader.ProgressUpdateListener progressUpdateListener;
// Leave it as it is
private int index;
public static void start(List<String> urls, ImageDownloader.ProgressUpdateListener listener) {
ChainModeCallbackHandler.urls = urls;
results = new ArrayList<>();
progressUpdateListener = listener;
//Start with the first task
ImageDownloader.getInstance(listener).download(urls.get(0), new ChainModeCallbackHandler(0));
}
private ChainModeCallbackHandler(int index) {
this.index = index;
}
@Override
public void onSuccess(String imagePath) {
results.add(imagePath);
afterCallback();
}
@Override
public void onFailure() {
afterCallback();
}
private void afterCallback() {
int nextIndex = index+1;
if (nextIndex<urls.size()) {
//Tasks are not completed yet. Do next task
ImageDownloader.getInstance(progressUpdateListener).download(urls.get(nextIndex),
new ChainModeCallbackHandler(nextIndex));
} else {
// All tasks completed. List "results" now holds the result
DemoActivity.isTasksInProgress = false;
}
}
}
并行执行任务。
优点 并行执行有时可以节省时间
import java.util.ArrayList;
import java.util.List;
public class ParallelModeCallbackHandler {
// List of args to start the task. Use pojo classes if your task has multiple args
private static List<String> urls;
// List of results
private static List<String> results;
// Leave it as it is
private static int count;
public static void start(List<String> urls, ImageDownloader.ProgressUpdateListener listener) {
ParallelModeCallbackHandler.urls = urls;
results = new ArrayList<>();
count = 0;
// Start all tasks
for (String url :
urls) {
//Replace with your task and its callback
ImageDownloader.getInstance(listener).download(url, new ImageDownloader.ImageDownloadCallback() {
@Override
public void onSuccess(String imagePath) {
results.add(imagePath);
afterCallback();
}
@Override
public void onFailure() {
afterCallback();
}
});
}
}
private ParallelModeCallbackHandler() {}
private static void afterCallback() {
if (++count==urls.size()) {
// All tasks completed. List "results" now holds the result
DemoActivity.isTasksInProgress = false;
}
}
}
使用CountDownLatch,我将在这里复制他们的用法示例以获得更好的语法突出显示(:
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}