是否有使用当前线程的ExecutorService?

Mic*_*urd 83 java concurrency

我所追求的是一种配置线程池使用的兼容方式.理想情况下,其余代码不应受到影响.我可以使用一个线程池与1个线程,但这不是我想要的.有任何想法吗?

ExecutorService es = threads == 0 ? new CurrentThreadExecutor() : Executors.newThreadPoolExecutor(threads);

// es.execute / es.submit / new ExecutorCompletionService(es) etc
Run Code Online (Sandbox Code Playgroud)

Nam*_*ter 76

您可以使用番石榴MoreExecutors.newDirectExecutorService(),或者MoreExecutors.directExecutor()如果您不需要ExecutorService.

如果包含番石榴太重了,你可以实现几乎同样好的东西:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 对于 Android,它是 _return Executors.unconfigurableExecutorService(instance);_ (2认同)

ove*_*ink 60

这是一个非常简单Executor(不是ExecutorService,介意你)的实现,只使用当前线程.从"实践中的Java并发"(基本阅读)中窃取这一点.

public class CurrentThreadExecutor implements Executor {
    public void execute(Runnable r) {
        r.run();
    }
}
Run Code Online (Sandbox Code Playgroud)

ExecutorService 是一个更复杂的界面,但可以用相同的方法处理.

  • 在Java8中,您可以将其简化为"Runnable :: run" (12认同)
  • 非常重要,我的副本在工作中失踪:-( (7认同)
  • +1:正如您所说,可以通过子类化AbstractExecutorService以相同的方式处理ExecutorService. (4认同)

lpa*_*zic 51

Java 8风格:

Executor e = Runnable::run;

  • 绝对肮脏.我喜欢它. (5认同)
  • 这是最好的肮脏@Ipandzic,它不寻常且简洁。 (5认同)

Eri*_*ner 12

我写了一个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();
    }
}
Run Code Online (Sandbox Code Playgroud)


Pet*_*rey 5

您可以使用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();
    }
});
Run Code Online (Sandbox Code Playgroud)

你只需要其中一个.

  • 注意,已经有了这个策略的实现,不需要定义自己的`java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy`. (8认同)
  • 创建一个最大池大小为0的ThreadPoolExecutor是不可能的.我想可以使用大小为0的blockingQueue重现行为,但是没有默认实现似乎允许这样做. (7认同)

fab*_*cci 5

为了测试目的,我不得不使用相同的“ CurrentThreadExecutorService”,尽管所有建议的解决方案都不错(特别是提到Guava方式的解决方案),但我想出了与Peter Lawrey 在这里建议的类似的东西。

正如Axelle Ziegler 在此处提到的那样,不幸的是,Peter的解决方案实际上无法正常工作,因为ThreadPoolExecutormaximumPoolSize构造函数参数上引入了检查(即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);
        }
    };
}
Run Code Online (Sandbox Code Playgroud)