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.