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