Parallel processing in Java; consultation needed, for example, for Runnanble / Callable interfaces

Suppose I have a set of objects that need to be analyzed in two different ways: they both take a relatively long time and include IO calls, I'm trying to figure out how / if I could optimize this part of my software, especially using multiple processors (the machine I'm sitting on for ex is an 8-core i7 that almost never exceeds 10% of the load at runtime).

I am new to parallel programming or multithreading (not sure what the correct term is), so I read some of the previous questions, especially paying attention to highly voted and informative answers. I am also in the process of going through the Oracle / Sun tutorial on concurrency .

Here is what I have thought so far;

  • The thread safe collection stores objects to be analyzed.
  • As soon as there are objects in the collection (they come in turn from a series of requests), a thread to the object starts
  • Each particular thread takes care of preliminary preliminary analyzes; and then calls the analysis.
  • Two analyzes are performed as Runnables / Callables and are thus invoked by the thread when necessary.

And my questions are:

  • This is a reasonable scheme, if not, how would you do it?
  • To make sure everything is not out of control, should I implement ThreadManager or something like that that starts and stops threads and redistributes them upon completion? For example, if I have 256 objects for analysis and a total of 16 threads, ThreadManager assigns the first finished thread to the 17th object for analysis, etc.
  • Is there a significant difference between Runnable / Callable, except that Callable can return a result? Otherwise, I should try to implement my own interface, in which case why?

Thanks,

+1
source share
4 answers
  • You can use BlockingQueue to hold your objects and create your threads there. This interface is based on the producer-consumer principle. The put () method blocks if your queue is full until there is still more space, and take () blocks if the queue is empty until some objects appear in the queue.

  • ExecutorService can help you manage your thread pool.

  • If you expect results from your spawned threads, then the Callable interface is a good idea to use, since you can start the calculation earlier and work in your code, assuming the results in Future-s. Regarding the differences with the Runnable interface, from Callable javadoc :

    The Callable interface is similar to Runnable, since both are for classes whose instances are potentially executed by another thread. However, Runnable does not return a result and cannot throw a checked exception.

Some common things you need to consider in your java concurrency searches:

  • Visibility does not arise due to defacto. volatile, AtomicReference and other objects in the java.util.concurrent.atomic package are your friends.
  • You need to carefully ensure the atomicity of complex actions through synchronization and locking.
+3
source

Your idea basically sounds. However, instead of creating threads directly or indirectly through some ThreadManager of your own design, use the Executor package from Java concurrency. He does everything you need, and other people have already taken the time to write and debug it. The worker manages the task queue, so you also do not need to worry about ensuring the thread safety queue.

There is no difference between Callable and Runnable, except that the former returns a value. Artists will process both.

Itโ€™s not clear to me whether you plan to take the step of preparing a separate task for analysis or turn it into one of them, and this task will not be solved for the other task of analysis halfway. I canโ€™t think of any reason to strongly prefer each other, but this is a choice that you should think about.

+3
source

Artists provide factory methods for creating thread pools. Specifically, Executors # newFixedThreadPool (int nThreads) creates a fixed-size thread pool that uses an unlimited queue. Also, if a thread terminates due to a failure, a new thread will be replaced instead. Therefore, in your specific example of 256 tasks and 16 threads, you would call

// create pool ExecutorService threadPool = Executors.newFixedThreadPool(16); // submit task. Runnable task = new Runnable(){};; threadPool.submit(task); 

An important issue is determining the correct number of threads for a thread pool. See if it helps. Effective thread count

+2
source

Sounds reasonable, but it's not as trivial to implement as it might seem. Perhaps you should check out the jsr166y project. This is probably the easiest solution to your problem.

0
source

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


All Articles