Synchronized Methods vs. Semaphore

When one-thread-access for synchronized methods is too restrictive, semaphores come to mind.


There is one important difference in these approaches.

Let's consider a code:

private Object synch = new Object();

public void synchronizedMethod1() {
    synchronized (synch) {
        synchronizedMethod2();
    }
}

public void synchronizedMethod2() {
    synchronized (synch) {
        System.out.println("Access to the resource acquired.");
    }
}

What happened by calling the synchronizedMethod1()?

Of course the access to the resource will be acquired because the synchronized block is in Java shared in within the thread. In other words, if the thread is already in the synchronized block will get all the others as well (protected by the same object).

Applying a semaphore (with the counter set to one) on the same code:

private Semaphore semaphore = new Semaphore(1);

public void synchronizedMethod1() throws InterruptedException {
    semaphore.acquire();
    synchronizedMethod2();
    semaphore.release();
}

public void synchronizedMethod2() throws InterruptedException {
    semaphore.acquire();
    System.out.println("Access to the resource acquired.");
    semaphore.release();
} 

And calling synchronizedMethod1() will freeze forever.

In this case acquire the synchronizedMethod1 the semaphore but synchronizedMethod2 fails on trying to acquire it again.

In general, this problem is caused by a weak design and can be solved by a simple refactoring:

public void synchronizedMethod1() throws InterruptedException {
    semaphore.acquire();
    resourceMethod();
    semaphore.release();
}

public void synchronizedMethod2() throws InterruptedException {
    semaphore.acquire();
    resourceMethod();
    semaphore.release();
}

private void resourceMethod() {
    System.out.println("Access to the resource acquired.");
}