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。