Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I have to synchronize on a List that is read by a stream?

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

like image 821
Anna Klein Avatar asked Aug 12 '17 17:08

Anna Klein


People also ask

Do read methods need to be synchronized?

if your shared object is either a read-only or immutable object, then you don't need synchronization, despite running multiple threads. The same is true with what threads are doing with an object if all the threads are only reading values then you don't require synchronization in Java.

Are streams synchronized?

STREAMS uses a synchronization-queueing mechanism that maximizes execution throughput. A synchronization queue is a linked list of structures. Each structure encapsulates a callback to a function attempting to access a resource.

Do streams modify original list?

That means list. stream(). filter(i -> i >= 3); does not change original list. All stream operations are non-interfering (none of them modify the data source), as long as the parameters that you give to them are non-interfering too.

What does synchronized list do?

The synchronizedList() method of java. util. Collections class is used to return a synchronized (thread-safe) list backed by the specified list. In order to guarantee serial access, it is critical that all access to the backing list is accomplished through the returned list.


1 Answers

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!
    }
like image 166
Roman Puchkovskiy Avatar answered Oct 24 '22 10:10

Roman Puchkovskiy