I've created a pool of 4 worker threads to process some files. In the test there's about 200 of them. The thread pool version is already about 3 times faster than doing it sequentially but there is room for improvement.
The biggest bottleneck (ignoring disk I/O) is that I need to instantiate a new MessageDigest object. In the single threaded version I just had 1. In this version I have 200.
What I was wondering was, is it possible to have a variable local to the thread in the work pool? That way (assuming no threads die) there would only be four instances of the MessageDigest object rather than 200...
Each task requires the digest so I'm not sure if there's a better way to do it...
UPDATE
I tried to use a ThreadLocal object but where should I create it? If I create it in the task itself, I guess it goes out of context when the task is completed. Each time a new instance is created. The code I have is:
ThreadLocal tl = new ThreadLocal();
hashMaker = tl.get();
if(hashMaker == null){
hashMaker = new GenerateSHA1();
tl.set(hashMaker);
}
This is done from inside the constructor of the task.
UPDATE
Okay making it static sort of works in that the object is not lost - but it's now highlighted a different issue. The work "tasks" are create in the Main thread and then added to the the ExecutorService with invokveAll().
Any ideas on how to work around this?
解决方案
Extend ThreadLocal for your class and override the initialValue() method. By default, it returns null.
private static class ThreadLocalGenerateSHA1 extends
ThreadLocal {
@Override
protected GenerateSHA1 initialValue() {
return new GenerateSHA1();
}
}
private static final ThreadLocalGenerateSHA1 generateSHA1 = new ThreadLocalGenerateSHA1();
...
On the tasks, simply call the get() method of generateSHA1. You do not need to call set().