I want to lock an object over multiple API requests such that only one request per user can enter a block of code.
Does synchronized(obj)
lock based on the object's reference or its hashCode()
function?
I.e. could I do:
synchronized("asdf") {
doSomethingNifty();
}
Here "asdf" has a unique hash but no unique reference.
When we use a synchronized block, Java internally uses a monitor, also known as monitor lock or intrinsic lock, to provide synchronization. These monitors are bound to an object; therefore, all synchronized blocks of the same object can have only one thread executing them at the same time.
Lock framework works like synchronized blocks except locks can be more sophisticated than Java's synchronized blocks. Locks allow more flexible structuring of synchronized code.
Synchronization is required to prevent several threads from accessing a resource allowing only one thread at a time. Java's synchronized blocks, denoted by the synchronized keyword, allow you to handle several threads at once. In each case, a thread must acquire and release a lock on the method or block.
If a thread wants to execute a static synchronized method, then the thread requires a class level lock.
Does synchronized(obj) lock based on the object's memory location or its toHash() function?
Neither. It is locking on the monitor associated with the the object. In terms of the JVM we don't talk about an object's memory address because it is relocatable and it's not the hash code (even in terms of Object.hashcode()
) because that is not unique.
In terms of what you should be locking on, it should be the same final
object. Something like:
private final Object lockObject = new Object();
...
synchronized (lockObject) {
// do stuff that needed to be protected
}
You want it to be final
so that multiple threads can be guaranteed to be locking on the same object reference that is not changing. private
is good so outside classes can't screw up the locking inside of a class.
Here "asdf" has a unique hash but no unique memory address.
"asdf"
does not have a unique hash since other strings might have the same hash and it actually may have a unique "memory address" across all usage of "asdf" in your application if the compiler stores it in the Java string pool. That means that some completely different class might also have the same bad pattern code block and would affect the synchronization of your class because it would be locking on the same String
object instance. That's why a private
lock object is so important.
While we are on the subject, you must also never synchronize on a mutable value like a non-final object like Boolean
or Integer
. The following pattern is used often and is very wrong:
Boolean value = false;
...
// really bad idea
synchronized (value) {
if (value) {
value = false;
} else {
value = true;
}
}
This is very wrong because the value
reference is changing. So one thread might lock on it and then change it's reference value so another thread would lock on another object and both threads would be within the synchronized
at the same time. It is even worse because with a Boolean
there are only 2 values of true
and false
which are constants so multiple classes would then be locking on the same references.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With