Radu Ionescu
Radu Ionescu

Reputation: 3532

Why intrinsic lock object do not require special treatment (static, final, volatile)?

In this oracle example of intrinsic locks and many more, the monitor object is never declared as volatile, final or nor it has any distinction from any other regular object

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}

There are plenty of questions that debate volatile versus synchronization blocks

and immutable objects

As a side note, I understand this subtle difference between declaring an object final versus immutability why-can-final-object-be-modified and why declaring the lock object as final would not make it immutable.

However, we have the famous pattern of the singleton class lazy initialization where the use of the volatile variables is essential.

public class SingletonDemo {
    private static volatile SingletonDemo instance;
    private SingletonDemo() { }

    public static SingletonDemo getInstance() {
        if (instance == null ) {
            synchronized (SingletonDemo.class) {
                if (instance == null) {
                    instance = new SingletonDemo();
                }
            }
        }

        return instance;
    }
}

which in the above code example uses the Class object as lock.

Since for an object which is accessed by multiple threads you need to use some mechanism as above to ensure atomic access, why is that for intrinsic lock object there is no need for any special treatment?

Upvotes: 1

Views: 355

Answers (3)

Gabe Sechan
Gabe Sechan

Reputation: 93668

It probably should be final. But final isn't anything really special- its only required in one special case (referencing a variable declared inside a function into an anonymous class). Any other case final is simply a reminder for the programmer to not overwrite the variable- you can remove every other use of the word final in your program and it will work perfectly. You're right, a programmer could assign to it and then cause problems. But if he doesn't, there's no issue. So go ahead and use final when you create one, but it isn't necessary for the program to compile.

As for static- depends on the usecase. Do you want to monitor all instances of a class, or each instance independently? In the first case, you use static in the second case you don't.

Volatile isn't needed because the object isn't actually being changed by the multiple threads. Its being synchronized on. This is completely different, and an older part of the Java language than volatile. There's no need to make the variable volatile as you won't be altering it, and the internal data structures used to monitor on an object already know they need to be thread safe (and in a stronger manner than volatile promises).

Upvotes: 0

user207421
user207421

Reputation: 310985

In this oracle example of intrinsic locks and many more, the monitor object is never declared as volatile, final or nor it has any distinction from any other regular object.

That's not true. See below.

Since for an object which is accessed by multiple threads you need to use some mechanism as above to ensure atomic access, why is that for intrinsic lock object there is no need for any special treatment?

It does have special treatment. It is synchronised on.

Upvotes: -1

markspace
markspace

Reputation: 11030

These locks don't need special treatment because the MsLunch object itself needs to be published before it can be seen by any additional threads.

public class MyMain {
  public static void main(String... args) {
    MsLunch lunch = new MsLunch();
    // ...

This is thread safe because local variables ("lunch") are not visible to more than one thread.

Next the class below makes the local reference visible to all threads in the system. When that happens we need to use volatile. The volatile keyword effectively creates a memory barrier that publish the object safely. This includes all writes made before the assignement including writes made internally when constructing the object.

C.f. Safe Publication

public class MyMain {

  public static volatile MsLunch publicLunch;

  public static void main(String... args) {
    MsLunch lunch = new MsLunch();
    publicLunch = lunch;
    //...
  }
}

Upvotes: 1

Related Questions