简体   繁体   中英

Java “static final” vs just “static” variable while locking

I have been reading about using static objects as locks and the most common example would be something like this:

public class MyClass1 {
  private static final Object lock = new Object();
  public MyClass1() {
    //unsync
    synchronized(lock) {
      //sync
    }
    //unsync
  }
}

My question is does lock have to be final? I understand it is good to put it as final to assure that nobody messes with the value, but will it work without final?

If you do not make the variable final , you may get a NullPointerException in the constructor of MyClass1 if you create the instance of MyClass1 in a different thread than the thread in which MyClass1 was loaded.

The final modifier guarantees safe publication of the lock in a way that not having final does not.

Also, if it's not final , it could be changed, leading to you locking on the wrong object instance.

You can find out more about the guarantees that the final modifier provides in terms of safe publication in the Java Language Specification Section 17.5 ("Final Field semantics") , which is in chapter 17 ("Threads and Locks").

Sure, it will work -- until you re-assign it. If lock is not final, somebody could assign another value to it ( lock = new Object() ). It's like replacing the locks in your door: if you still have the old keys, you won't be able to use the lock anymore.

Making lock final will prevent that from happening, so it's always a good idea to do it.

Basically you have to make sure that once the lock object is created nobody messes up with it by any means. Hence, you have to make it constant which we do by using static final . So, by creating a constant we are making sure that our lock object is created as soon as the class is loaded and never modify that in application lifetime.

Bonus :

Another way of doing same is by using static initializer . This is well suited in the cases where you wish to do the lock object assignment in more than one statements. An example of same below:

public class Test {
    private static final Test lockObject;

    static {
        System.out.println("Hello");
        lockObject = new Test();
    }

    public static void main(String[] args) {
        synchronized (lockObject) {
            //your code goes here
        }
    }
}

Maybe it's more intuitive if written in a different way: it's pretty much the same as this

public class MyClass {
    static Lock myLock = new ReentrantLock();
    public MyClass1() {
        //unsync
        myLock.lock();
        //sync
        myLock.unlock();
        //unsync
    }
}

with the same consequences of myLock being final or not.

If it's not final and gets reassigned, the lock status will be irrelevant.

I'd recommend using the Lock class anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM