我建议看一下使用FutureCallbacks这是番石榴图书馆的一部分。
这将允许您执行的操作是为您触发的每项任务创建一个ListenableFuture
。根据你的情况,这听起来像这样将由Runnable
表示,但你可以很容易地使用一个Callable
。当这些任务都发射了,你最终会与这些ListenableFuture
对象,它可以被“扁平化”到一个单一的ListenableFuture
代表的所有任务完成的列表。这是通过与方法Futures.allAsList(...)
:
final List<ListenableFuture<T>> futures = ...
final ListenableFuture<List<T>> combinedFuture = Future.allAsList(futures);
现在,你有一个ListenableFuture
代表所有任务的完成,你可以很容易地通过添加FutureCallback
听其完成完成时被调用:
Futures.addCallback(future, new FutureCallback<List<String>>() {
@Override
public void onFailure(final Throwable arg0) {
// ...
}
@Override
public void onSuccess(final List<String> arg0) {
// ...
}
}
现在,一旦这些任务完成,我们需要更新UI以通知用户。要做到这一点,我们必须确保UI更新SWT UI线程上发生回:
Display.getCurrent().asyncExec(new Runnable() {
@Override
public void run() {
// Update the UI
}
});
注意,这可以很容易的的onSuccess内进行()上面的方法,这样的任务的结果可能是用过的。我们可以很容易地通过一些ListeningExecutorService
.submit(...)调用来执行后台执行(以免阻塞UI线程 - 在我的示例中,您可以自由输入文本框,而任务在后台运行),抓住所有的ListenableFutures
,并添加一个回调被调用完成后,这将跳回UI线程,使UI更新。
完整的示例:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
public class CallbackExample {
private final Display display;
private final Shell shell;
private final Text output;
private final ListeningExecutorService executor;
public CallbackExample() {
display = new Display();
shell = new Shell(display);
shell.setLayout(new FillLayout());
executor = MoreExecutors.listeningDecorator(Executors
.newFixedThreadPool(20));
final Composite baseComposite = new Composite(shell, SWT.NONE);
baseComposite
.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
baseComposite.setLayout(new GridLayout());
output = new Text(baseComposite, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
output.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Button button = new Button(baseComposite, SWT.PUSH);
button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
button.setText("Start tasks");
button.addSelectionListener(new SelectionAdapter() {
@SuppressWarnings("synthetic-access")
@Override
public void widgetSelected(final SelectionEvent e) {
// Start tasks when the button is clicked
startTasks();
}
});
}
private void startTasks() {
// Create a List to hold the ListenableFutures for the tasks
final List<ListenableFuture<String>> futures = new ArrayList<ListenableFuture<String>>();
// Submit all the tasks for execution (in this case 100)
for (int i = 0; i < 100; i++) {
final ListenableFuture<String> future = executor
.submit(new Callable<String>() {
@Override
public String call() throws Exception {
// Do the work! Here we sleep to simulate a long task
Thread.sleep(2000);
final long currentMillis = System
.currentTimeMillis();
System.out.println("Task complete at "
+ currentMillis);
return "Task complete at " + currentMillis;
}
});
// Add the future for this task to the list
futures.add(future);
}
// Combine all of the futures into a single one that we can wait on
final ListenableFuture<List<String>> future = Futures
.allAsList(futures);
// Add the callback for execution upon completion of ALL tasks
Futures.addCallback(future, new FutureCallback<List<String>>() {
@Override
public void onFailure(final Throwable arg0) {
System.out.println("> FAILURE");
}
@SuppressWarnings("synthetic-access")
@Override
public void onSuccess(final List<String> arg0) {
System.out.println("> SUCCESS");
// Update the UI on the SWT UI thread
display.asyncExec(new Runnable() {
@Override
public void run() {
final StringBuilder sb = new StringBuilder();
for (final String s : arg0) {
sb.append(s + "\n");
}
final String resultString = sb.toString();
output.setText(resultString);
}
});
}
});
}
public void run() {
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
executor.shutdownNow();
display.dispose();
}
public static void main(final String... args) {
new CallbackExample().run();
}
}
有一个看看这篇文章:https://stackoverflow.com/questions/1250643/how-to-wait-for-all-threads-to-finish -using-executorservice/36718097#36718097 –