I'm new in Java concurrency, so i ask what is the best way to perform action like this:
I have a static method which matches a sub image within an image. It looks like that:
public static Point match(final BufferedImage subimage, final BufferedImage image)
The method returns null if nothing was matched, else it returns the Point of the match.
Now I have 40 different sub images for one (big) image, which I want to match in parallel. Each second I will get a new (big) image in which I need to search those 40 smaller images over and over again. I need the return values of each call to to match method at the end of the match task in my main task, so I can analyze it. Furthermore I need to use as many CPU cores as possible for this task.
How can I accomplish that? I have read a lot about ExecutorService, Task, Runnable and so on. Most examples only show how to print something on the console in paralles. I am really confused which way I should go in my scenario: How to pass the values and how to get the results? How should the layout of the class(es) look like? Also I have no idea what is the way to go if I create 40 tasks a second (it will take some time to setup the task, right?)
Code would be great to explain it :)
ExecutorService EXEC = Executors. newCachedThreadPool(); List<Callable<Result>> tasks = new ArrayList<Callable<Result>>(); for (final Object object: objects) { Callable<Result> c = new Callable<Result>() { @Override public Result call() throws Exception { return compute(object); } }; tasks.
Parallel tasks are split into subtasks that are assigned to multiple workers and then completed simultaneously. A worker system can carry out both parallel and concurrent tasks by working on multiple tasks at the same time while also breaking down each task into sub-tasks that are executed simultaneously.
You can execute streams in serial or in parallel. When a stream executes in parallel, the Java runtime partitions the stream into multiple substreams. Aggregate operations iterate over and process these substreams in parallel and then combine the results.
Use a CompletionService
, more likely a ExecutorCompletionService
.
class Matcher {
ExecutorService threadPool = Executors.newCachedThreadPool();
private List<BufferedImage> subimages; // populate it yourself
public static Point match(BufferedImage subimage, BufferedImage image) {
// Your implementation
}
public List<Point> match(BufferedImage image) {
CompletionService<Point> completionService = new ExecutorCompletionService(threadPool);
int size = subimages.size();
List<Point> results = new ArrayList<>(size);
for (BufferedImage subimage: subimages) {
completionService.submit(()->match(subimage, image));
}
for (int i = 0; i < size; i++) {
Point point = completionService.take().get();
if (point != null) {
results.add(point);
}
}
return results;
}
}
If you want to use all the CPU, you probably want to change your ExecutorService
to Executors.newWorkStealingPool()
. Be careful with this though!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With