Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Java Synchronized compare locked objects?

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.

like image 655
Jason Avatar asked May 21 '13 16:05

Jason


People also ask

Does synchronized method lock object?

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.

What is the difference between lock and synchronized in Java?

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.

What is synchronization in Java How does it help to lock a resource?

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.

Is lock required for synchronized method?

If a thread wants to execute a static synchronized method, then the thread requires a class level lock.


1 Answers

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.

like image 122
Gray Avatar answered Oct 05 '22 22:10

Gray