ExecutorService中的持久变量(Java)

时间:2011-10-20 09:36:52

标签: java concurrency threadpool

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

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

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

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

更新

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

    ThreadLocal<GenerateSHA1> tl = new ThreadLocal<GenerateSHA1>();

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

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

更新

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

有关如何解决此问题的任何想法?

3 个答案:

答案 0 :(得分:3)

为您的课程延长ThreadLocal并覆盖initialValue()方法。默认情况下,它返回null。

private static class ThreadLocalGenerateSHA1 extends
  ThreadLocal<GenerateSHA1> {

  @Override
  protected GenerateSHA1 initialValue() {
    return new GenerateSHA1();
  }

}

private static final ThreadLocalGenerateSHA1 generateSHA1 = new ThreadLocalGenerateSHA1();

...

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

答案 1 :(得分:0)

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

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

修改

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

答案 2 :(得分:0)

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

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