0

Assuming we had this class

final class Foo {
    private final Set<String> bar = new HashSet<>();

    public Foo() {
        bar.add("one");
        bar.add("two");
        bar.add("three");
    }

    public boolean contains(final String s) {
        return bar.contains(s);
    }
}

Would it be threadsafe to instantiate Foo and call contains of this object from multiple threads?

  1. The reference to the collection is private and final. No one can access directly the collection.
  2. The only write access occurs in the constructor
  3. After the constructor is executed, the collection will only read and not modified.

If not, is there an pure Java alternative to Guava's immutable collections?

duffymo
  • 305,152
  • 44
  • 369
  • 561
Vertex
  • 2,682
  • 3
  • 29
  • 43
  • I would say this is thread safe. Inheritance might introduce other nuances, but I'd sleep at night with this. – duffymo Jun 17 '14 at 12:15
  • possible duplicate of [Java concurrency: is final field (initialized in constructor) thread-safe?](http://stackoverflow.com/questions/6457109/java-concurrency-is-final-field-initialized-in-constructor-thread-safe) – Joe Jun 17 '14 at 12:18
  • 1
    @Joe, you're right. This question is exactly the same. If you can, please close my question. – Vertex Jun 17 '14 at 12:23

4 Answers4

2

Your Foo and bar are actually immutable. it is thread-safe.

Kent
  • 189,393
  • 32
  • 233
  • 301
  • thanks, but the `HashSet` isn't immutable, only the reference to it. – Vertex Jun 17 '14 at 12:18
  • @Vertex you are right. let's say, give you an object `foo`, with your codes, how can you change the inner set `bar`? If your `bar` is "reay only" thing, it is thread safe. – Kent Jun 17 '14 at 12:20
1

It depends on how the access to this object is published. While the bar Set is final and thus guaranteed to visible to all threads, the population of the map is not guaranteed to happen before the conclusion of constructor.

This, however would be guaranteed to be thread safe regardless of how the object was created and made available.

private final Set<String> bar;

public Foo() {
    bar = new HashSet<String>(Arrays.asList("one", "two", "three"));
}

Testing initialization safety of final fields

https://stackoverflow.com/a/23995782/676877

Community
  • 1
  • 1
Brett Okken
  • 6,210
  • 1
  • 19
  • 25
0

As long as this is accessed in a read only manner I think you should be safe. Also , java offers immutable versions of it's base collections exposed through static methods on the Collections class , so I would look at Collections.unmodifiableSet() .

Also , while you add strings in your example, and strings themselves are immutable in java , you would be in trouble if you added mutable objects and then decided to modify/read them from different threads (you would need synchronized blocks in this case).

omu_negru
  • 4,642
  • 4
  • 27
  • 38
0

It is thread safe provided that

1) The constructor does not leak a reference before its fully constructed.

2) No one has any way to access the collection.

3) No subclass can be created which can edit the collection.

As a general rule though, if you want to implement this use an immutable collection from guava, that makes the behaviour explicit to the programmer, and it is then safe to return the whole map. I think that in pure java you can return an unmodifiable view of a collection.

phil_20686
  • 4,000
  • 21
  • 38