我有一个方法可以在火中执行异步请求而忘记时尚。
方法实现如下:
private void publishWorkItem(final Object payload, final ZkWorkCompleteCallback callback)
{
if (payload == null)
throw new NullPointerException();
final ExecutorService executor = Executors.newSingleThreadExecutor(PUBLISH_WORK_THREAD_FACTORY);
try
{
executor.execute(() -> {
try
{
if (callback != null)
{
final ZkWorkItem retval = publishWorkItem(payload);
callback.onCompleted(retval);
}
}
catch (final InterruptedException e)
{
// suppressed
}
catch (final Exception e)
{
LOGGER.error("Unhandled exception", e);
if (callback != null)
callback.onError(e);
}
});
}
finally
{
executor.shutdown();
}
}
问题是我为每个异步请求创建新的ExecutorService Executors.newSingleThreadExecutor
而不是使用固定的线程池。原因是publishWorkItem(payload)
方法使用CountDownLatch#await()
,而Watcher
反过来将阻止正在执行的线程,因为它等待publishWorkItem(payload)
完成。这可能会迅速耗尽固定大小的游泳池。
final CountDownLatch latch = new CountDownLatch(1);
zkClient.exists(pathToWatch, new Watcher()
{
@Override
public void process(final WatchedEvent event)
{
try
{
extractAndDelete(baos, event.getPath());
}
catch (final Exception e)
{
LOGGER.error("Unable to perform cleanup", e);
}
finally
{
latch.countDown();
}
}
}, true);
------ THIS IS THE PROBLEM (Blocks current thread) ------
latch.await();
的简化代码
{{1}}
所以我的问题是:是否有更好的解决此类问题的方法。
我确实对应用程序进行了分析,但我没有看到任何性能问题,我担心的是它创建了大量的线程。
答案 0 :(得分:0)
为什么不使用ExecutorService.newCachedThreadPool()
?
根据javadoc,它适合您的用例
这些池通常会提高执行许多短期异步任务的程序的性能......如果可用,将重用以前构造的线程
不是在publishWorkItem()
的每次调用中创建新的单线程池,而是创建一个缓存的线程池一次并用于所有查询。线程数的上限为Integer.MAX_VALUE
,因此您不会受限于固定线程池,但它应该创建更少的线程。