Reputation: 2171
if I have a Thread sensitive List I go usually like this while iterating over it:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
I wonder if I use list.stream() and do then some operations over the stream like filter etc., if I also have to put the list into a synchronize block or does the stream makes a copy of the list?
Thanks
Upvotes: 10
Views: 5813
Reputation: 1182
Yes, you have to synchronize access to the list when using streams in the same way you would do without streams. Synchronization should be taken care of by a user.
A stream by itself doesn't guarantee to create any copy of the original sequence. It can make a copy during some intermediate computations (e.g. sort
), but you should not rely on that. And doing this for each usage of a stream would be a waste of resources since streams are not reusable.
If a user wants a stream to operate over a copy, they have to manually create a copy or use CopyOnWriteArrayList
instead of ArrayList
, for example.
Moreover, keep in mind that streams are lazy. The underlying sequence is not accessed until a terminal operation (e.g. collect
, forEach
) is executed.
Upvotes: 3
Reputation: 140457
A stream can be seen as a "view" on the original data. This means: it is part of their nature to avoid making copies.
Only operations like sorting require creating a copy of the input. Thus: when your input can be changed by another thread - then you need to protect against that.
Upvotes: 0
Reputation: 11835
Stream operations use spliterator()
method internally.
Here is the spliterator()
method from ArrayList
:
public Spliterator<E> spliterator() {
checkForComodification();
return new ArrayListSpliterator<E>(ArrayList.this, offset,
offset + this.size, this.modCount);
}
It checks for comodification, so it looks like stream()
operations have to be inside synchronized blocks in your case.
Also, spliterator()
of SynchronizedCollection
(in Collections
) has comment
public Spliterator<E> spliterator() {
return c.spliterator(); // Must be manually synched by user!
}
which is analogous to the comment in iterator()
:
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!
}
which shows the same: synchronization is needed around stream()
operations (at least, if iterator()
requires such a synchronization).
And the most convincing: stream()
method from SynchronizedCollection
:
public Stream<E> stream() {
return c.stream(); // Must be manually synched by user!
}
Upvotes: 9