Java™ 教程(Lock物件)

博弈發表於2019-01-19

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();
    }
}

上一篇:高階併發物件

下一篇:執行器

相關文章