The "Lock" and "Condition" interface give programmers a high degree of control over locking. However, in most situations, you don't need that control -- you can use a mechanism that is built into the Java language. Ever since version 1.0, every object in Java has an intrinsic lock. IF a method is declared with the "synchronized" keyword, the object's lock protects the entire method ( not like "Lock" and "Condition" mechanism can protect a critical block). That is, to call the method, a thread must acquire the intrinsic object lock.
In other words,
public synchronized void method() {
... ...
... ...
}
is equivalent of
public void method() {
this.intrinsicLock.lock();
try {
... ...
... ...
} finally {
this.intrinsicLoc.unlock();
}
}
The "transfer" method of the simulated bank program can be refined like this: (I recommend readers to consider the comments within the following codes)
public synchronized void transfer(int from, int to, double amount) {
try {
while (accounts[from] < amount) {
notify(); //call this method to activate a waiting to be notified thread on this object.
//It is equivalent to the call to "signal" method on a condition object.
wait(); //this method make the current thread deactivated, give up the lock, waiting to be notified by others.
//It is equivalent to the call to "await" method on a condition object.
}
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf(" %10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total Balance: %10.2f\n", getTotalBalance());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
notifyAll(); //it is equivalent to the call to "signalAll" method on a condition object.
} finally {
notify();
}
}
The intrinsic locks and conditions have some limitations. Among them:
You could not interrupt a thread that is trying to acquire a lock.
You can not specify a timeout when trying to acquire a lock.
Having a single condition per lock can be inefficient.
Synchronized Block:
There is a second mechanism for acquiring the lock: by entering a synchronized block. When a thread enters a block of the form:
synchronize (obj) { //this is the syntax for a synchronized block
critical section
}
then it acquire the lock for "obj" .
You will sometimes find "ad-hoc" locks, such as:
public class bank {
private double[] accounts;
private Object lock = new Object();
... ...
... ...
public void transfer(int from, int to, double amount) {
synchronized (lock) { //an ad-hoc lock.
//implicitly, every class extends the "Object" superclass, so that this syntax
//can obtain any object's intrinsic lock; in this case,
//can obtain the "accounts" 's intrinsic lock. In this way,
//the atomic operation can be ensured.
accounts[from] -= amount;
accounts[to] += amount;
}
System.out.println(...);
}
}