Java 5 has a ReentrantLock implementation of the Lock interface. Meaning if the same thread tries to acquire the lock again, it will allow that. It does have information about which thread is holding the lock. The following code will not cause a deadlock.

1
2
3
4
5
6
7
8
9
10
11
12
Lock l=new ReentrantLock(true);
public void funcReentrantLock(int level) {
  System.out.println("entered funcReentrantLock: " + Thread.currentThread().getName() + " at level " + level);		
  if ( level == 0 )
    return;
 
  l.lock();
  System.out.println(Thread.currentThread().getName() + " locked at level " + level);
  funcReentrantLock(level-1);
  l.unlock();
  System.out.println(Thread.currentThread().getName() + " unlocked at level " + level);
}

Semaphore’s on the other hand are non-re entrant meaning if the same thread locks and then re-locks it will cause a deadlock. If the same thread tries to acquire the lock again, it wont allow that. It does not have information which thread is holding the lock. The following code will cause a deadlock.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Semaphore available = new Semaphore(1, true);
public void funcNonReentrantLock(int level) {
  System.out.println("entered funcNonReentrantLock: " + Thread.currentThread().getName() + " at level " + level);		
  try {
    if ( level == 0 )
	return;
    available.acquire();
    System.out.println(Thread.currentThread().getName() + " acquire at level " + level);
    funcNonReentrantLock(level-1);
    available.release();
    System.out.println(Thread.currentThread().getName() + " release at level " + level);
  } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
}

The synchronized keyword is a re-entrant lock. Why use one over the other? Well for starters it seems like re-entrant lock performs much better. Also, the lock interface provides some other api methods like trylock() which acquires the lock only if it is free at time of invocation.