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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 07:56:56  来源:igfitidea点击:

Is there an ExecutorService that uses the current thread?

javaconcurrency

提问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();
    }
}

ExecutorServiceis 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 ExecutorServicebased 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 ThreadPoolExecutoron the maximumPoolSizeconstructor parameter (i.e. maximumPoolSizecan't be <=0).

正如 Axelle Ziegler在这里提到的,不幸的是,由于ThreadPoolExecutormaximumPoolSize构造函数参数中引入了检查(即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);
        }
    };
}