3

In Java Concurrency In Practice, the author stated that

  1. Immutable objects can be published through any mechanism
  2. Immutable objects can be used safely by any thread without additional synchronization, even when synchronization is not used to publish them.

Does it mean that the following idioms are safe to publish immutable objects?

public static List<ImmutableObject> list = new ArrayList<ImmutableObject>();

// thread A invokes this method first
public static void methodA () {
    list.add(new ImmutableObject());
}

// thread B invokes this method later
public static ImmutableObject methodB () {
    return list.get(0);
}

Would there be any data race? (which means thread B may not be able to see the Immutable Object in the list added by thread A)

Thank you very much.


More, the author said that the following code is safe if Resource is immutable.

@NotThreadSafe
public class UnsafeLazyInitialization {
    private static Resource resource;

    public static Resource getInstance() {
        if (resource == null)
            resource = new Resource();  // unsafe publication
        return resource;
    }
}

Section16.3 The guarantee of initialization safety allows properly constructed immutable objects to be safely shared across threads without synchronization, regardless of how they are published even if published using a data race. (This means that unsafeLazyInitialization is actually safe if Resource is immutable.)

For the 2nd part of this question, it is discussed in detail in another question (click here)

Cœur
  • 37,241
  • 25
  • 195
  • 267
ben ben
  • 259
  • 3
  • 9
  • Neither is thread safe and I doubt that JCiP says that the `UnsafeLazyInitialization` class is thread safe if Resource is immutable because it is not the case. In particular, resource in `if (resource == null)` could be non null while resource in `return resource` could be null due to instructions reordering. You could solve that by using a local variable. – assylias Jan 31 '13 at 09:21
  • Thank you for replying. The author stated this point in Section16.3, I have added supplementary content to the question. (I am not sure whether i have misinterpreted what the author actually meant) – ben ben Jan 31 '13 at 10:19
  • Interesting. I would tend to believe whatever is in that book because they know better! But I don't understand it. If Resource is immutable, I understand that you can either see an instance null or fully constructed, which is a guarantee provided by the final semantics. But I don't understand how this can prevent reordering. I'll think about it. – assylias Jan 31 '13 at 10:54
  • I have raised this issue in [a question](http://stackoverflow.com/questions/14624365/immutability-and-reordering) which has attracted interesting answers (although at the moment, the most upvoted one is wrong: concurrent stuff IS difficult to get right!). – assylias Jan 31 '13 at 16:59

4 Answers4

5

Yes, you are correct, there is a data race.

Only the ImmutableObject is immutable and can be shared safely between threads, your List, however, does not have these same guarantees, so there is a data race between adding the ImmutableObject and retrieving it.

In JCIP, the authors meant immutable objects are safe to publish in the sense that you don't have to worry about doing things like making defensive copies.

As to:

Immutable objects can be used safely by any thread without additional synchronization, even when synchronization is not used to publish them.

This statement means that given 2 threads with an immutable object A that they both acquired through any means, they can both use object A without worrying about thread-safety issues.

Alex DiCarlo
  • 4,851
  • 18
  • 34
3

Your List<ImmutableObject> list container object is not immutable. Hence, add and get method on it will not be threadsafe. These methods need to be synchronized for concurrent access from multiple threads.

Bimalesh Jha
  • 1,464
  • 9
  • 17
1

Your question suggests that you are anticipating section 5.3 - blocking queues and the producer consumer pattern. Here is something similar using a blocking queue:

public class Blocking
{
   private BlockingQueue<ImmutableObject> queue = new ArrayBlockingQueue<ImmutableObject>(10);

   public void methodA() {
      queue.add(new ImmutableObject());
   }

   public ImmutableObject methodB() throws InterruptedException
   {
      return queue.take();
   }
   static class ImmutableObject
   {

   }
}

The blocking queue is highly mutable - but is designed to be thread safe so you can use it without extra synchronization. As long as the objects that you are passing are immutable the entire design is thread safe.

In the example above, methodB uses "take" which will block until methodA is called to put something in the queue. Or until the thread is interrupted at which point it would exit via an InteruptedException

Guido Simone
  • 7,912
  • 2
  • 19
  • 21
0

Yes there is definite chance of data race. Here is a situation:

Although Thread A is inside methodA and then Thread B would be executing methodB, there is no guarantee that methodA has returned before methodB. If, unfortunately, methodB has already returned while methodA is yet to return, there would be high chance to get IndexOutOfBoundsException:

// thread A invokes this method first
public static void methodA () {
    //assume control is taking time at this point, while thread B already returned!!!

    list.add(new ImmutableObject());
}

// thread B invokes this method later
public static ImmutableObject methodB () {
    return list.get(0);
}