Yes, there is a way to create only one instance of object per thread, you should use ThreadLocal<ServiceHandler>
and declare it as a static field. This would create only one instance of object per thread.
You can check http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html this for official documentation.
Share objects between tasks in a thread pool but not between threads in Java [duplicate]
-
01-06-2022 - |
質問
I'm trying to create a multithreaded application in Java using ExecutorService thread pools. The application basically queries a third party service for data about a given keyword. Since I have many keywords and each request takes some time to generate, I would like to query the service in parallel. The requests are made through a ServiceHandler object which takes care of authentication and parsing the results out.
In my initial implementation, I create a new Callable for each keyword and creates a new ServiceHandler object to query the service. For some reason, this runs faster than sharing a singleton ServiceHandler object across all Callable. However, with large input data sets, I'm running into memory issues because it is creating new objects for each input keyword.
Is there a way to still use ExecutorService but only create a distinct instance of ServiceHandler for each worker thread? For example, if I have 1000 keywords and a fixed pool of 20 threads, I want to only create one ServiceHandler for each thread (20 total) while still having one Callable for each keyword(1000 total).
I tried adding a static ThreadLocal object to each Callable objects that returns a new ServiceHandler in its initialValue() , but it seems like only one ServiceHandler is being created? I can post my code for this, but I'm not even sure if this is the right approach.
解決
他のヒント
I think this is a producer-consumer problem. You have a BlockingQueue which may contain as many keywords as you like, and a pool of 20 consumer/service threads.
The service threads work like this:
while (true) {
Keyword k = queue.pop();
process(k);
}
Your producer thread just fills up the queue with the keywords that you want to process and one of the service threads will take care of it.
I figure out what my particular issue is. The correct solution is to use a ThreadLocal object, but the issue with my implementation was that I was calling the ThreadLocal.get() method when I was constructing each Callable. Since the construction takes place in the main Thread and NOT the ExecutorService's worker threads, I was always getting the same ServiceHandler instance, which made it perform similar to a singleton.
Once I moved the call to get() to the Callable's call() method, then the correct execution happens.