It solves deadlock problems because the thread that enters `synchronized` is interruptibly locked and only backed out on exceptions, where other threads are enforced to wait without an ability to back out when in queue to acquire the lock.
Secondly, lock objects has Lock.newCondition() method which returns a Condition instance that is bound to the lock instance, which allows the lock acquirer to set a specific condition (e.g. when two other threads attempts to acquire the lock when I haven't unlocked it yet) and allows automatic unlocking before wait returns.