当我运行以下代码时:
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
线程中。特别是在调用线程中调用了callable的调用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...
正如可以看到,callable的调用发生在另一个线程pool-1-thread-1
中。我想我可以解释为什么会这样;也许是因为线程池可以有(最多)1个可用的线程,所以第一个Callable被调度到另外的线程,否则被BlockingCallable
使用。
我的问题是如何创建一个ExecutorService
来执行DirectExecutorService
所做的事情而不必人为地烧掉一个永远不会完成的可调用线程?
我为什么要问这个?
MoreExecutors.newDirectExecutorService()
- 如果可以的话。ThreadPoolExecutor
不允许将maxThreads
设置为0.如果允许的话会很奇怪,但如果确实如此,那么这也解决了我的问题。CallerRunsPolicy
会导致所有call
全部 Callable
s在调用者的线程中执行。所以,我想把我的经验和黑客放在那里,所以其他人可以节省最后燃烧的时间,试图理解这一点。 :(如果无法升级到番石榴17.0 +,是否有更好/更惯用的方式来实现DirectExecutorService行为?
答案 0 :(得分:2)
如果无法升级到番石榴17.0 +,是否有更好/更惯用的方式来实现DirectExecutorService行为?
如果这是您唯一的问题,则应使用MoreExecutors.sameThreadExecutor()
。在将其移至新方法之前基本为newDirectExecutorService()
(并添加了directExecutor()
),请参阅Javadoc:
自:18.0(自10.0以来呈现为
MoreExecutors.sameThreadExecutor()
)
BTW:你应该真的升级到最新的番石榴,你使用的是近六岁的番石榴!