Lock物件
同步程式碼依賴於簡單的可重入鎖,這種鎖易於使用,但有許多限制,java.util.concurrent.locks包支援更復雜的鎖定語法,我們不會詳細檢查這個包,而是將重點放在其最基本的介面Lock上。
Lock
物件的工作方式與同步程式碼使用的隱式鎖定非常相似,與隱式鎖一樣,一次只有一個執行緒可以擁有一個Lock
物件,Lock
物件還通過其關聯的Condition物件支援wait
/notify
機制。
Lock
物件優於隱式鎖的最大優點是它們能夠退出獲取鎖的嘗試,如果鎖立即不可用或超時到期之前(如果指定),則tryLock
方法退出,如果另一個執行緒在鎖被獲得之前傳送中斷,則lockInterruptibly
方法將退出。
讓我們使用Lock
物件來解決我們在活性中看到的死鎖問題,Alphonse和Gaston訓練自己注意朋友什麼時候要鞠躬。我們通過要求我們的Friend
物件必須在繼續執行bow
之前獲取兩個參與者的鎖來對此進行建模,以下是改進模型Safelock的原始碼。為了演示這個語法的多功能性,我們假設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();
}
}