Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe publication when values are read in synchronized methods

My question concerns safe publication of field values in Java (as discuessed here Java multi-threading & Safe Publication).

As I understand it, a field can be safely read (meaning access from multiple threads will see the correct value) if:

  • read and write are synchronized on the same monitor
  • field is final
  • field is volatile

If my understanding is correct the following class should not be thread-safe since the initial value is written without these characteristics. However I find it hard to believe that I need to make first volatile even though it is only accessed from a synchronized method.

public class Foo {

    private boolean needsGreeting = true;

    public synchronized void greet() {
        if (needsGreeting) {
            System.out.println("hello");
            needsGreeting = false;
        }
    }
}

Am I missing something? Is above code correct and if so why? Or is it necessary in such cases to make first volatile or use a final AtomicBoolean or something like that in addition to accessing it from a synchronized method.

(Just to clarify, I am aware, that if the initial value was written in a synchronized method, it would be thread-safe even without the volatile keyword.)

like image 391
Joe23 Avatar asked Oct 27 '10 11:10

Joe23


People also ask

Is synchronized method thread-safe?

Thread safe means: method becomes safe to be accessed by multiple threads without any problem at the same time. synchronized keyword is one of the way to achieve 'thread safe'. But Remember:Actually while multiple threads tries to access synchronized method they follow the order so becomes safe to access.

When should you synchronize a method?

We need to synchronize the shared resources to ensure that at a time only one thread is able to access the shared resource. If an Object is shared by multiple threads then there is need of synchronization in order to avoid the Object's state to be getting corrupted. Synchronization is needed when Object is mutable.

Why we use synchronized on the block when we can use it on the method?

A Synchronized block is a piece of code that can be used to perform synchronization on any specific resource of the method. A Synchronized block is used to lock an object for any shared resource and the scope of a synchronized block is smaller than the synchronized method.


1 Answers

There is no happens-before relationship between the end of a constructor and method invocations, and as such it is possible for one thread to start constructing the instance and make the reference available and for another thread to acquire that reference and start calling the greet() method on a partially constructed object. The synchronization in greet() does not really address that issue.

If you publish an instance via the celebrated double-checked locking pattern, it becomes easier to see how. If there was such a happens-before relationship, it should have been safe even if DCLP is used.

public class Foo {
    private boolean needsGreeting = true;

    public synchronized void greet() {
        if (needsGreeting) {
            System.out.println("Hello.");
            needsGreeting = false;
        }
    }
}

class FooUser {
    private static Foo foo;

    public static Foo getFoo() {
        if (foo == null) {
            synchronized (FooUser.class) {
                if (foo == null) {
                    foo = new Foo();
                }
            }
        }
        return foo;
    }
}

If multiple threads call FooUser.getFoo().greet() at the same time, one thread might be constructing the Foo instance, but another thread may find a non-null Foo reference prematurely, and call greet() and find needsGreeting is still false.

An example of this is mentioned in Java Concurrency in Practice (3.5).

like image 78
sjlee Avatar answered Oct 21 '22 18:10

sjlee