Suppose we have a list of workers like this :
List<Worker> workers = new ArrayList<>();
workers.add(new Worker(1));
workers.add(new Worker(2));
workers.add(new Worker(3));
workers.add(new Worker(4));
workers.add(new Worker(5));
I want to find the first worker who finished his job, so :
Worker first = workers.parallelStream().filter(Worker::finish).findFirst().orElse(null);
but there's a problem, I don't want to wait for all workers to finish their jobs and then find the first, but the first worker As soon as he finished his job!
public class Test {
public static void main(String[] args) {
List<Worker> workers = new ArrayList<>();
workers.add(new Worker(1));
workers.add(new Worker(2));
workers.add(new Worker(3));
workers.add(new Worker(4));
workers.add(new Worker(5));
Worker first = workers.parallelStream().filter(Worker::finish).findFirst().orElse(null);
if (first != null) {
System.out.println("id : " + first.id);
}
}
static class Worker {
int id;
Worker(int id) {
this.id = id;
}
boolean finish() {
int t = id * 1000;
System.out.println(id + " -> " + t);
try {
Thread.sleep(t);
} catch (InterruptedException ignored) {
}
return true;
}
}
}
is there any way to achieve it using java.util.Stream
?
Thanks.
The findFirst() method finds the first element in a Stream. So, we use this method when we specifically want the first element from a sequence. When there is no encounter order, it returns any element from the Stream. According to the java.
In Java 8 Stream, the findFirst() returns the first element from a Stream, while findAny() returns any element from a Stream.
Stream findFirst() vs findAny() – ConclusionUse findAny() to get any element from any parallel stream in faster time.
Java Parallel Streams is a feature of Java 8 and higher, meant for utilizing multiple cores of the processor. Normally any java code has one stream of processing, where it is executed sequentially.
You seem to have a serious misconception about Stream
. Stream
s are not meant to launch workers. In fact, if you use findFirst
it may happen that it starts no worker but the first one. And so it also doesn’t wait “for all workers to finish” but only for currently pending threads. But since you have a rather small stream it might be the case that all workers have been started already because there are as much threads available in your environment. But this is not a guaranteed behavior.
Note that if you use a sequential stream instead of a parallel stream it will for sure process the first item only (as it returns true
) and none of the other. But since the stream implementation can’t predict that result it will respect you request to “accelerate” the operation via parallel execution and may start processing more items in advance using more threads.
When you use your finish
method as the filter of the Stream, it means that in order to evaluate the filter's predicate for a specific Worker, the Worker has to finish its work.
When you run this code as a parallel Stream, however, it's possible that the filter would be applied on multiple Workers at the same time, in which case, the first one to finish would give you the output. However, you have no control over how many threads the parallel Stream will use. It may decide that some of the Workers should be processed on the same thread, in which case some of them won't be processed at all (since your terminal operation requires that only one Worker finishes its processing).
Therefore, if your goal is that finish
is executed for all Workers at the same time, you can't use a Stream (not even a parallel Stream).
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