當我運行下面的代碼:如何使用純ThreadPoolExecutor獲取MoreExecutors.newDirectExecutorService()行爲?
package foo.trials;
import com.google.common.util.concurrent.MoreExecutors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class DirectExecutorService {
private static final Logger logger_ = LoggerFactory.getLogger(DirectExecutoService.class);
public static void main(String[] args) {
boolean useGuava = true;
final ExecutorService directExecutorService;
if (useGuava) {
directExecutorService = MoreExecutors.newDirectExecutorService();
} else {
directExecutorService = new ThreadPoolExecutor(
0, 1, 0, TimeUnit.DAYS,
new SynchronousQueue<Runnable>(),
new ThreadPoolExecutor.CallerRunsPolicy());
directExecutorService.submit(new BlockingCallable());
}
Future<Boolean> future = directExecutorService.submit(new MyCallable());
try {
logger_.info("Result: {}", future.get());
} catch (InterruptedException e) {
logger_.error("Unexpected: Interrupted!", e);
} catch (ExecutionException e) {
logger_.error("Unexpected: Execution exception!", e);
}
logger_.info("Exiting...");
}
static class MyCallable implements Callable<Boolean> {
static final Random _random = new Random();
@Override
public Boolean call() throws Exception {
logger_.info("In call()");
return _random.nextBoolean();
}
}
static class BlockingCallable implements Callable<Boolean> {
Semaphore semaphore = new Semaphore(0);
@Override
public Boolean call() throws Exception {
semaphore.acquire(); // this will never succeed.
return true;
}
}
}
我得到以下輸出
13:36:55.960 [main] INFO a.t.DirectExecutoService - In call()
13:36:55.962 [main] INFO a.t.DirectExecutoService - Result: true
13:36:55.963 [main] INFO a.t.DirectExecutoService - Exiting...
注意,所有的執行發生在main
線程。特別是可調用的調用get在調用線程中調度。當然,這是從MoreExecutors.newDirectExecutorService()
預計那裏不會有什麼驚喜。
當我將變量useGuava
設置爲false
時,我得到了類似的結果。
13:45:14.264 [main] INFO a.t.DirectExecutoService - In call()
13:45:14.267 [main] INFO a.t.DirectExecutoService - Result: true
13:45:14.268 [main] INFO a.t.DirectExecutoService - Exiting...
但,如果我註釋掉以下行
directExecutorService.submit(new BlockingCallable());
然後我得到以下輸出。
13:37:27.355 [pool-1-thread-1] INFO a.t.DirectExecutoService - In call()
13:37:27.357 [main] INFO a.t.DirectExecutoService - Result: false
13:37:27.358 [main] INFO a.t.DirectExecutoService - Exiting...
正如人們所看到的可調用的調用發生在不同的線程pool-1-thread-1
。我想我可以解釋爲什麼會發生這種情況。也許因爲線程池可以有(最多)1個可用的線程,所以第一個Callable被分派到該額外線程,否則該線程被BlockingCallable
消耗。
我的問題是,如何創建一個ExecutorService
,將DirectExecutorService
做什麼,而不必人爲地燃燒線程與永不完成的可調用?
爲什麼我問這個?
- 我有一個在版本11.0使用番石榴的代碼庫。我需要避免將其升級到17.0+ - 如果可以的話,它提供
MoreExecutors.newDirectExecutorService()
。 ThreadPoolExecutor
不允許將maxThreads
設置爲0.如果允許,那將會很奇怪,但如果確實如此,那也能解決我的問題。- 最後,我很驚訝地發現這種行爲 - 我本以爲(錯誤地),使用
CallerRunsPolicy
會導致的call
所有Callable
所有s到在調用者的線程中執行。所以,我想把我的經驗和竅門放在那裏,這樣別人就可以節省最後燃燒的時間來試圖理解這一點。 :(
有沒有更好/更地道的方式來實現DirectExecutorService樣的行爲如果不能升級到番石榴17.0+?
就是這樣,謝謝!關於升級的觀點很好。 –