[英]Java Executor for “main” thread
I'd like to create an Executor
from the "main" thread of a program (similar to the main looper in Android), and then just run until it has processed everything submitted to it: 我想从程序的“主”线程(类似于Android中的主循环程序)创建一个Executor
,然后运行直到它处理了提交给它的所有内容:
public class MyApp {
private static Callable<Integer> task = () -> {
// ... return an int somehow ...
};
public static void main(String[] args) throws ExecutionException, InterruptedException {
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
Thread main = Thread.currentThread();
ExecutorService executorService = Executors.newSingleThreadExecutor(r -> main);
service.submit(task).addListener(() -> {
/// ... do something with the result ...
}, executorService);
executorService.awaitTermination(100, TimeUnit.SECONDS);
}
}
But I get an IllegalThreadState
exception: 但是我得到了一个IllegalThreadState
异常:
SEVERE: RuntimeException while executing runnable MyApp$$Lambda$20/0x00000008000a6440@71f06a3c with executor java.util.concurrent.Executors$FinalizableDelegatedExecutorService@47add263
java.lang.IllegalThreadStateException
at java.base/java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:926)
at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1343)
at java.base/java.util.concurrent.Executors$DelegatedExecutorService.execute(Executors.java:687)
at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1137)
at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:957)
at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:726)
at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.afterRanInterruptibly(TrustedListenableFutureTask.java:131)
at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:133)
at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:78)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
I could just start an ExecutorService
on a new thread, and then await that, but that seems wasteful. 我可以在新线程上启动ExecutorService
,然后等待它,但这似乎很浪费。
Is there a good way to create an Executor
from the current thread, and wait for it to process everything that has been submitted to it? 有没有什么好方法可以从当前线程创建Executor
,并等待它处理已提交给它的所有内容?
You are perhaps looking for something like a CompletionService
: you submit tasks to this, and it gives you them back in order of completion. 您可能正在寻找类似CompletionService
东西:您向此任务提交任务,并且它按完成顺序将其返回。
ExecutorService service = Executors.newFixedThreadPool(1);
ExecutorCompletionService<Integer> comp = new ExecutorCompletionService<>(service);
comp.submit(task);
// ... I assume you want to submit N tasks.
for (int i = 0; i < N; ++i) {
Future<Integer> future = comp.take();
Integer result = future.get();
// ... do something with the result ...
}
This will process the items as soon as they are complete. 项目完成后,将立即对其进行处理。 If you are able to wait until you have everything, and then process it in one go, you can use Guava's Futures.allAsList
: 如果您能够等到拥有所有东西之后再进行一次处理,则可以使用Guava的Futures.allAsList
:
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
List<Callable<Integer>> tasks = ...;
List<ListenableFuture<Integer>> futures = new ArrayList<>();
for (Callable<Integer> task : tasks) {
futures.add(service.submit(task));
}
ListenableFuture<List<Integer>> resultsFuture = Futures.allAsList(futures);
List<Integer> results = resultsFuture.get();
// Process the results.
MoreExecutors.newDirectExecutorService()
使用番石榴的MoreExecutors.newDirectExecutorService()
This will make sure that the code submitted will be executed in the same thread of the ThreadPool. 这将确保提交的代码将在ThreadPool的同一线程中执行。 I know, it's not the main thread, but at least you don't create other new threads just for the listener, just like you wanted. 我知道,它不是主线程,但至少您不会像想要的那样仅为侦听器创建其他新线程。
import com.google.common.util.concurrent.*;
import org.junit.jupiter.api.Test;
import java.util.concurrent.*;
class ExecutorTest {
private static Callable<Integer> task = () -> {
System.out.println("in call: " + Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(1);
return 0;
};
@Test
void test() throws InterruptedException {
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
ExecutorService executor = MoreExecutors.newDirectExecutorService();
service.submit(task).addListener(() -> {
System.out.println("in listener: " + Thread.currentThread().getName());
}, executor);
executor.awaitTermination(2, TimeUnit.SECONDS);
}
}
You are trying to execute the callback in the main thread. 您正在尝试在主线程中执行回调。 The straightforward approach is to call get()
: 直接的方法是调用get()
:
YourResult result = service.submit(task).get();
/* Do something with your result... */
If you want to execute a callback asynchronously, you might be interested in a CompletionStage
如果要异步执行回调,则可能对CompletionStage
感兴趣
CompletableFuture.runAsync(task).thenAccept(r -> /* do something with result */);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.