同步代碼依賴于一種簡單的可重入鎖。這種鎖很容易使用,但有很多限制。 java.util.concurrent.locks 包支持更復(fù)雜的鎖定方式。我們不會詳細(xì)的研究這個包,而是將重點放在它最基本的接口Lock上。
鎖對象非常像 synchronized 代碼使用的隱式鎖。與隱式鎖一樣,一次只有一個線程擁有一個 Lock 對象。Lock 對象還通過其關(guān)聯(lián)的 Condition 對象支持 wait /notify 機(jī)制。
Lock 對象比隱式鎖好的一點是它能退出嘗試獲取鎖。如果鎖定不是立即可用或在超時 到期之前(如果指定的話),tryLock 方法將會退出。如果另一個線程在獲取鎖之前發(fā)出中斷,lockInterruptibly 方法將會退出。
讓我們使用 Lock 對象來解決我們在 Liveness 中看到的死鎖問題。Alphonse 和 Gaston 已經(jīng)訓(xùn)練自己注意什么時候朋友要鞠躬。我們通過要求我們的 Friend 對象在繼續(xù)前進(jìn)之前必須獲取兩個參與者的鎖來模擬這種改進(jìn)。這里是改進(jìn)的模型 Safelock 的源代碼。為了證明這個習(xí)慣用法的多樣性,我們假定 Alphonse 和Gaston 是如此迷戀他們的新的安全鞠躬能力,他們不能停的彼此鞠躬:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Random;
public class Safelock {
static class Friend {
private final String name;
private final Lock lock = new ReentrantLock();
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public boolean impendingBow(Friend bower) {
Boolean myLock = false;
Boolean yourLock = false;
try {
myLock = lock.tryLock();
yourLock = bower.lock.tryLock();
} finally {
if (! (myLock && yourLock)) {
if (myLock) {
lock.unlock();
}
if (yourLock) {
bower.lock.unlock();
}
}
}
return myLock && yourLock;
}
public void bow(Friend bower) {
if (impendingBow(bower)) {
try {
System.out.format("%s: %s has"
+ " bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
} finally {
lock.unlock();
bower.lock.unlock();
}
} else {
System.out.format("%s: %s started"
+ " to bow to me, but saw that"
+ " I was already bowing to"
+ " him.%n",
this.name, bower.getName());
}
}
public void bowBack(Friend bower) {
System.out.format("%s: %s has" +
" bowed back to me!%n",
this.name, bower.getName());
}
}
static class BowLoop implements Runnable {
private Friend bower;
private Friend bowee;
public BowLoop(Friend bower, Friend bowee) {
this.bower = bower;
this.bowee = bowee;
}
public void run() {
Random random = new Random();
for (;;) {
try {
Thread.sleep(random.nextInt(10));
} catch (InterruptedException e) {}
bowee.bow(bower);
}
}
}
public static void main(String[] args) {
final Friend alphonse =
new Friend("Alphonse");
final Friend gaston =
new Friend("Gaston");
new Thread(new BowLoop(alphonse, gaston)).start();
new Thread(new BowLoop(gaston, alphonse)).start();
}
}