Java 是否有使用当前线程的 ExecutorService?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6581188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there an ExecutorService that uses the current thread?
提问by Michael Rutherfurd
What I am after is a compatible way to configure the use of a thread pool or not. Ideally the rest of the code should not be impacted at all. I could use a thread pool with 1 thread but that isn't quite what I want. Any ideas?
我所追求的是一种兼容的方式来配置线程池的使用与否。理想情况下,其余代码根本不应该受到影响。我可以使用带有 1 个线程的线程池,但这并不是我想要的。有任何想法吗?
ExecutorService es = threads == 0 ? new CurrentThreadExecutor() : Executors.newThreadPoolExecutor(threads);
// es.execute / es.submit / new ExecutorCompletionService(es) etc
采纳答案by overthink
Here's a really simple Executor
(not ExecutorService
, mind you) implementation that only uses the current thread. Stealing this from "Java Concurrency in Practice" (essential reading).
这是一个非常简单的Executor
(不是ExecutorService
,请注意)实现,它只使用当前线程。从“Java Concurrency in Practice”(基本阅读)中窃取。
public class CurrentThreadExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
ExecutorService
is a more elaborate interface, but could be handled with the same approach.
ExecutorService
是一个更精细的界面,但可以用相同的方法处理。
回答by Peter Lawrey
You can use the RejectedExecutionHandler to run the task in the current thread.
您可以使用 RejectedExecutionHandler 在当前线程中运行任务。
public static final ThreadPoolExecutor CURRENT_THREAD_EXECUTOR = new ThreadPoolExecutor(0, 0, 0, TimeUnit.DAYS, new SynchronousQueue<Runnable>(), new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
r.run();
}
});
You only need one of these ever.
您只需要其中之一。
回答by Eric Obermühlner
I wrote an ExecutorService
based on the AbstractExecutorService
.
我写了一个ExecutorService
基于AbstractExecutorService
.
/**
* Executes all submitted tasks directly in the same thread as the caller.
*/
public class SameThreadExecutorService extends AbstractExecutorService {
//volatile because can be viewed by other threads
private volatile boolean terminated;
@Override
public void shutdown() {
terminated = true;
}
@Override
public boolean isShutdown() {
return terminated;
}
@Override
public boolean isTerminated() {
return terminated;
}
@Override
public boolean awaitTermination(long theTimeout, TimeUnit theUnit) throws InterruptedException {
shutdown(); // TODO ok to call shutdown? what if the client never called shutdown???
return terminated;
}
@Override
public List<Runnable> shutdownNow() {
return Collections.emptyList();
}
@Override
public void execute(Runnable theCommand) {
theCommand.run();
}
}
回答by NamshubWriter
You can use Guava's MoreExecutors.newDirectExecutorService()
, or MoreExecutors.directExecutor()
if you don't need an ExecutorService
.
您可以使用 Guava 的MoreExecutors.newDirectExecutorService()
,或者MoreExecutors.directExecutor()
如果您不需要ExecutorService
.
If including Guava is too heavy-weight, you can implement something almost as good:
如果包含 Guava 太重,你可以实现几乎同样好的东西:
public final class SameThreadExecutorService extends ThreadPoolExecutor {
private final CountDownLatch signal = new CountDownLatch(1);
private SameThreadExecutorService() {
super(1, 1, 0, TimeUnit.DAYS, new SynchronousQueue<Runnable>(),
new ThreadPoolExecutor.CallerRunsPolicy());
}
@Override public void shutdown() {
super.shutdown();
signal.countDown();
}
public static ExecutorService getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
static ExecutorService instance = createInstance();
}
private static ExecutorService createInstance() {
final SameThreadExecutorService instance
= new SameThreadExecutorService();
// The executor has one worker thread. Give it a Runnable that waits
// until the executor service is shut down.
// All other submitted tasks will use the RejectedExecutionHandler
// which runs tasks using the caller's thread.
instance.submit(new Runnable() {
@Override public void run() {
boolean interrupted = false;
try {
while (true) {
try {
instance.signal.await();
break;
} catch (InterruptedException e) {
interrupted = true;
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}});
return Executors.unconfigurableScheduledExecutorService(instance);
}
}
回答by lpandzic
Java 8 style:
Java 8 风格:
Executor e = Runnable::run;
Executor e = Runnable::run;
回答by fabriziocucci
I had to use the same "CurrentThreadExecutorService" for testing purposes and, although all suggested solutions were nice (particularly the one mentioning the Guava way), I came up with something similar to what Peter Lawrey suggested here.
我不得不使用用于测试目的相同的“CurrentThreadExecutorService”,尽管所有建议的解决方案都不错(尤其是一提的番石榴方式),我想出了类似于彼得Lawrey建议的东西在这里。
As mentioned by Axelle Ziegler here, unfortunately Peter's solution won't actually work because of the check introduced in ThreadPoolExecutor
on the maximumPoolSize
constructor parameter (i.e. maximumPoolSize
can't be <=0
).
正如 Axelle Ziegler在这里提到的,不幸的是,由于ThreadPoolExecutor
在maximumPoolSize
构造函数参数中引入了检查(即maximumPoolSize
不能是<=0
),彼得的解决方案实际上不会起作用。
In order to circumvent that, I did the following:
为了避免这种情况,我做了以下事情:
private static ExecutorService currentThreadExecutorService() {
CallerRunsPolicy callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
return new ThreadPoolExecutor(0, 1, 0L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), callerRunsPolicy) {
@Override
public void execute(Runnable command) {
callerRunsPolicy.rejectedExecution(command, this);
}
};
}