내가 추구하는 것은 스레드 풀 사용 여부를 구성하는 호환 가능한 방법입니다. 이상적으로 나머지 코드는 전혀 영향을받지 않아야합니다. 스레드가 1 개인 스레드 풀을 사용할 수 있지만 그게 내가 원하는 것이 아닙니다. 어떤 아이디어?
ExecutorService es = threads == 0 ? new CurrentThreadExecutor() : Executors.newThreadPoolExecutor(threads);
// es.execute / es.submit / new ExecutorCompletionService(es) etc
답변
여기 정말 간단 Executor
(하지 ExecutorService
만 현재 스레드를 사용하는 당신을 마음) 구현. “실습에서 Java 동시성”(필수 읽기)에서 이것을 훔칩니다.
public class CurrentThreadExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
ExecutorService
보다 정교한 인터페이스이지만 동일한 접근 방식으로 처리 할 수 있습니다.
답변
당신은 구아바의를 사용할 수 있습니다 MoreExecutors.newDirectExecutorService()
, 또는 MoreExecutors.directExecutor()
당신이 필요하지 않은 경우 ExecutorService
.
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);
}
}
답변
자바 8 스타일 :
Executor e = Runnable::run;
답변
나는 썼다 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();
}
}
답변
테스트 목적으로 동일한 “CurrentThreadExecutorService”를 사용해야했으며 제안 된 모든 솔루션이 훌륭했지만 (특히 Guava 방식을 언급 한 솔루션 ) Peter Lawrey가 여기서 제안한 것과 유사한 것을 생각해 냈습니다 .
Axelle Ziegler가 여기 에서 언급했듯이 , 안타깝게도 Peter의 솔루션은 생성자 매개 변수 ThreadPoolExecutor
에 도입 된 검사로 인해 실제로 작동하지 않습니다 maximumPoolSize
(예 : maximumPoolSize
불가능 <=0
).
이를 우회하기 위해 다음을 수행했습니다.
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);
}
};
}
답변
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();
}
});
이것들 중 하나만 필요합니다.