[java] 현재 스레드를 사용하는 ExecutorService가 있습니까?

내가 추구하는 것은 스레드 풀 사용 여부를 구성하는 호환 가능한 방법입니다. 이상적으로 나머지 코드는 전혀 영향을받지 않아야합니다. 스레드가 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();
    }
});

이것들 중 하나만 필요합니다.


답변