Search code examples
javamultithreadingsynchronized

Why would I ever create a separate mutex/lock object?


I am modifying some concurrent code at work and recently read through Java's docs on Intrinsic Locks and Synchronization.

Given that every object has an intrinsic lock, why would I ever create a separate object for the purposes of controlling access to a particular item?

I recognize that there may be a use case where the item of interest is not a malloc'd Object, (int vs Integer) and therefore doesn't have an intrinsic lock but... assuming that we are concerned about synchronizing some static Object, is there anything to lose?

e.g.:

public class main {
    public static void main (String[] args){
        Integer foo = 10;
        
        synchronized(foo){
            foo ++;
        }
    }
}

If I wanted to update foo from multiple threads, synchronously, why wouldn't I just use the object that I want to modify? Is this less performant? I see lots of synchronized(this), and separate instances where we may make a lock object for the purposes of synchronization:

public class main {
    public static void main (String[] args){
        Integer foo = 10; 
        Object fooLock = new Object();
        
        synchronized(fooLock){
            foo ++;
        }
    }
}

Why would I ever create fooLock, when I could instead use the object of actual interest? Is this actually discouraged (not idiomatic), or is there a practical reason not to do this?

I am thinking of doing the first approach (synchronized(foo)) for a static socket connection object, but it concerns me that I have not seen discussion of this. Am I missing something?


Solution

  • This is a comment, not an answer to your question.


    Your two examples are not equivalent. The second one prevents more than one thread* from entering the synchronized block at the same time, but the first one can allow many threads to be in the block at the same time.

    That's because, in the first one, synchronized(foo) locks whichever Integer object the foo variable happens to refer to at a given moment in time, but the foo++ statement reassigns foo so that it refers to a different object. Different threads could all be in the block at the same time, with each of them synchronized on a different object.

    In the second example, fooLock is effectively immutable. It always refers to the same Object instance. Since every thread is trying to synchronize on the same object as every other thread, they will be forced to go through the block one at a time.


    * Actually, both of your examples are complete programs that never create any new threads. In my comment, I'm imagining what would happen if the body of your main(...) function actually were in some other function that was called by many threads within some larger program.