2

Is the compute() function thread safe? Will multiple threads loop correctly over the list?

class Foo {

    private List<Integer> list;

    public Foo(List<Integer> list) {
        this.list = list;
    }

    public void compute() {
        for (Integer i: list) {
            // do some thing with it 
            // NO LIST modifications 
        }
    }
}
4
  • 3
    Is the list you pass as an argument susceptible to be modified elsewhere? Commented Apr 30, 2015 at 7:51
  • you have not synchronized the method thus it is not thread safe. secondly, as you list is not a static one thus multiple thread would loop over with no issues, provided the list is initialized properly. Commented Apr 30, 2015 at 7:51
  • When writing to a List the thread safety depends on the implementation of the list you are using. When only reading from a list you don't have to worry about Threadsafety Commented Apr 30, 2015 at 7:53
  • @SaurabhJhunjhunwala synchronizing the method compute does nothing about modifications of the list from other methods/classes. Commented Apr 30, 2015 at 7:56

6 Answers 6

1

Considering that data does not mutate (as you mentioned in the comment) there will not be any dirty / phantom reads.

Sign up to request clarification or add additional context in comments.

1 Comment

the comment seems to be limited to "no modifications within compute". Could be modified elsewhere.
1

If the list is created specifically for the purposes of that method, then you're good to go. That is, if the list isn't modified in any other method or class, then that code is thread safe, since you're only reading.

A general recommendation is to make a read-only copy of the collection, if you're not sure the argument comes from a trustworthy origin (and even if you are sure).

this.list = Collections.unmodifiableList(new ArrayList<Integer>(list));

Note, however, that the elements of the list must also be thread-safe. If, in your real scenario, the list contains some mutable structure, instead of Integer (which are immutable), you should make sure that any modifications to the elements are also thread-safe.

Comments

0

If you can guarantee that the list is not modified elsewhere while you're iterating over it that code is thread safe.

I would create a read-only copy of the list though to be absolutely sure that it won't be modified elsewhere:

class Foo {

    private List<Integer> list;

    public Foo(List<Integer> list) {
        this.list = Collections.unmodifiableList(new ArrayList<>(list));
    }

    public void compute() {
        for (Integer i: list) {
            // do some thing with it 
            // NO LIST modifications 
        }
    }
}

If you don't mind adding a dependency to your project I suggest using Guava's ImmutableList:

        this.list = ImmutableList.copyOf(list);

It is also a good idea to use Guavas immutable collections wherever you're using collections that aren't changing since they are inherently thread safe due to being immutable.

7 Comments

As list is private and no reference is published, there is absolutely no need to wrap it into an unmodifiable list.
It is passed in by reference to the constructor so there definitely exists references to the list outside the class.
Nope. It is copied: new ArrayList<>(list).
In my answer, yes. Not in the original question. To use unmodifiableList we need to make a copy since it only returns an immutable view of the underlying list. Collections.unmodifiableList(list) would accomplish nothing since the original list could still be modified outside the class. Using immutable variables wherever possible is a good practice so I'm not going to change my answer.
Exactly. That's why the unmodifiable list is useless: If you already create a copy, you don't need to wrap it into an unmodifiable list.
|
0

You can easily inspect the behavior when having for example 2 threads:

public class Test {

    public static void main(String[] args) {
        Runnable task1 = () -> { new Foo().compute(); };
        Runnable task2 = () -> { new Foo().compute(); };
        new Thread(task1).start();
        new Thread(task2).start();
    }

}

If the list is guaranteed not to be changed anywhere else, iterating on it is thread safe, if you implement compute to simply print the list content, debugging your code should help you understanding it is thread safe.

Comments

0

There is thread safe list in cocncurent library. If you want thread-safe collections always use it. Thread-safe list is CopyOnWriteArrayList

Comments

0

This version

class Foo {
    private final List<Integer> list;

    public Foo(List<Integer> list) {
        this.list = new ArrayList<>(list);
    }

    public void compute() {
        for(Integer i: list) {
             // ...
        }
    }
}

is thread-safe, if following holds:

  1. list arg to ctor can't be modified during ctor run time (e.g., it is local variable in caller) or thread-safe itself (e.g., CopyOnWriteArrayList);
  2. compute won't modify list contents (just as OP stated). I guess compute should be not void but return some numeric value, to be of any utility...

5 Comments

No it isn't; the constructor is not thread safe! In order to copy the elements of the original list an iteration is needed...
@Victor why are you making the list as final, then you would not be able to modify the elements in the list. If we want to make the method thread safe and simple option is synchronize the method.
@SaurabhJhunjhunwala You are still able to modify the contents of a list or the state of the object even if it's made final. final merely forbids changing the reference your field points to.
Marking it as final won't accomplish anything since the loop will be implemented using Iterators which won't be affected if the reference changes while we're iterating.
@fge you right ctor has no thread-safety guarantee, however, Foo object itself is thread-safe in respect to it's state, once constructed. I guess, this is what OP asked for...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.