ExecutorService中的持久变量(Java)

我已经创建了一个包含4个工作线程的池来处理一些文件。 在测试中,大约有200个。 线程池版本已经比顺序执行快3倍,但还有改进的余地。

最大的瓶颈(忽略磁盘I / O)是我需要实例化一个新的MessageDigest对象。 在单线程版本中我只有1.在这个版本中我有200。

我想知道的是,是否有可能在工作池中有一个本地变量? 这样(假设没有线程死亡)只有MessageDigest对象的四个实例而不是200 …

每个任务都需要摘要,所以我不确定是否有更好的方法来做…

UPDATE

我试图使用ThreadLocal对象,但我应该在哪里创建它? 如果我在任务本身创建它,我想它在任务完成时就会脱离上下文。 每次创建新实例时。 我的代码是:

ThreadLocal tl = new ThreadLocal(); hashMaker = tl.get(); if(hashMaker == null){ hashMaker = new GenerateSHA1(); tl.set(hashMaker); } 

这是从任务的构造函数内部完成的。

UPDATE

好吧,让它成为静态的工作,因为对象不会丢失 – 但它现在突出显示了一个不同的问题。 工作“任务”在主线程中创建,然后使用invokveAll()添加到ExecutorService。

关于如何解决这个问题的任何想法?

为您的类扩展ThreadLocal并覆盖initialValue()方法。 默认情况下,它返回null。

 private static class ThreadLocalGenerateSHA1 extends ThreadLocal { @Override protected GenerateSHA1 initialValue() { return new GenerateSHA1(); } } private static final ThreadLocalGenerateSHA1 generateSHA1 = new ThreadLocalGenerateSHA1(); ... 

在任务上,只需调用generateSHA1的get()方法即可。 您不需要调用set()

您可以将对象池用于消息摘要对象。 在您的情况下,将池大小设置为4。

apache commons提供了出色的池API: http : //commons.apache.org/pool/

您可以通过扩展它来获取ThreadPoolExecutor的beforeExecute和afterExecute方法的帮助。 在扩展类中,创建4个MessageDigest对象,并以循环方式将它们分配给beforeExecute(…)中的每个任务。

 private static final Executor executor = new MyThreadPoolExecutor(10, 10, 50000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(100)); 

编辑

我觉得Ravi Bhatt提到的对象池选项是简单而优雅的想法。 创建一个池并让任务从池中请求MessageDigest。