Java: Create a large number of Callables or extend the result of an iterator to threads?

I wrote an image management application. My manipulation code should apply to all images (up to 1 million per folder) in a folder.

So far, for each image in the folder, I created a Callable (which is a working one for image processing) and added it to the ArrayList . Then I use the invokeAll method for FixedThreadPool to parallelize the work.

However, my question is: Is this a good design? I have some doubts that adding 1 million elements to the list of arrays in the first place makes sense. I thought about passing the iterator (by file) to all threads and letting each thread take the next element and process it (with a blocking problem, of course, unfortunately) - but does it make sense?

+4
source share
2 answers

It sounds fine, even if it is not very efficient and does not scale very well. An alternative design could be:

  • create an ArrayBlockingQueue<File> larger than your FixedThreadPool (let's say twice as much)
  • create a FileVisitor , call it ImageFileVisitor , which in the visitFile method puts visited file in the queue is a blocking call, so it will wait until the queue is full
  • create as many Callable as the size of your pool and make each one take from the queue and do what they should do

Note. The thread pool size should be fairly small. If image processing is very difficult, use the number of processors for the size, if it is somewhat trivial and most of the time is spent reading / writing files, use a smaller size.

+3
source

FixedThreadPool uses LinkedBlockingQueue of Integer.MAX_VALUE :

 public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } 

Thus, its affectively non-blocking, since you could use offer / put million Runnable instances for it, certainly this is an unreasonable use of memory to store millions of objects, although your fixedPoolSize would be comparatively much smaller, say, 5/10.

One approach that would directly improve this scenario is to use FixedThreadPool with a finite queue size:

 int nThreads = 10; int maxQSize = 1000; ExecutorService service = new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(maxQSize)) 

With the above call, your put will block 1000 runnables in Q , but as soon as some of them end, put will continue. Performing invokeAll , there will be 10 running threads and no more than 1000 executable instances.

+1
source

Source: https://habr.com/ru/post/1484187/


All Articles