Мне нужен совместимый способ настроить использование пула потоков или нет. В идеале остальная часть кода вообще не должна подвергаться влиянию. Я мог бы использовать пул потоков с одним потоком, но это не совсем то, что я хочу. Любые идеи?
ExecutorService es = threads == 0 ? new CurrentThreadExecutor() : Executors.newThreadPoolExecutor(threads);
// es.execute / es.submit / new ExecutorCompletionService(es) etc
java
concurrency
Майкл Резерферд
источник
источник
AbstractExecutorService
похоже, кстати.Runnable::run
Вы можете использовать Guava
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); } }
источник
Стиль Java 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(); } }
источник
terminated
не получит выгоды от синхронного доступа на основе кода, который на самом деле здесь. Операции с 32-битными полями в Java атомарны.Вы можете использовать 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(); } });
Вам понадобится только один из них.
источник
java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
.Мне пришлось использовать тот же «CurrentThreadExecutorService» для целей тестирования, и, хотя все предложенные решения были хорошими (особенно то, которое упоминает способ Guava ), я придумал нечто похожее на то, что предложил здесь Питер Лоури .
Как отметил Аксель Ziegler здесь , к сожалению , решение Петра будет на самом деле не работает из - за проверки введенных в
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); } }; }
источник