用ReentrantLock和Condition實現線程間通信


在Java多線程中,除了使用synchronize關鍵字來實現線程之間的同步互斥,還可以使用JDK1.5中新增的RetrantLock類來實現同樣的效果。RetrantLock類的擴展功能也更加強大,比如具有嗅探鎖定,多路分支通知等功能,在使用上也比synchronize更為靈活。

借助於Condition對象,RetrantLock可以實現類似於Object的wait和notify/notifyAll功能。使用它具有更好的靈活性,在一個Lock對象里面可以創建多個Condition(對象監視器)實例,線程對象可以注冊在指定的Condition對象中,從而可以有選擇性的進行線程通知,實現多路通知功能,在調度線程上更加靈活。

每一個 Lock 可以有任意數據的 Condition 對象, Condition 是與 Lock 綁定的,所以就有 Lock 的公平性特性:如果是公平鎖,線程為按照FIFO的順序從 Condition.await 中釋放,如果是非公平鎖,那么后續的鎖競爭就不保證FIFO順序了。

下面是一個生產者、消費者的示例:

/*
 * 買家線程,當書店中有書的時候買書
 */
public class Buyer extends Thread {
    private BookStore bookStore;

    public Buyer(BookStore bookStore) {
        this.bookStore = bookStore;
    }

    @Override
    public void run() {
        while (true) {
            bookStore.removeBook();
        }
    }
}
/*
 * 售貨員線程,當書店中還有空位,買進書籍
 */
public class Seller extends Thread {
    private BookStore bookStore;
    public Seller(BookStore bookStore) {
        this.bookStore = bookStore;
    }

    @Override
    public void run() {
        while (true) {
            bookStore.addBook();
        }
    }
}
import java.util.ArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/*
 * 書店類
 */
public class BookStore {
    private ArrayList books = new ArrayList();
    private ReentrantLock lock = new ReentrantLock(false);
    private Condition buyCondition = lock.newCondition();
    private Condition sellCondition = lock.newCondition();
    public void addBook() {
        lock.lock();
        while (books.size() >= 1) {
            try {
                System.out.println(Thread.currentThread().getName() + "等待圖書售出");
                sellCondition.await();  //售貨員等待書店出現空位
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        books.add(1);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "購入了一本書,剩余:" + books.size());
        buyCondition.signal();  //通知買家買書
        lock.unlock();
    }

    public void removeBook() {
        lock.lock();
        while (books.size() <= 0) {
            try {
                System.out.println(Thread.currentThread().getName() + "等待購入圖書");
                buyCondition.await();  //買家等待書店進書
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        books.remove(0);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "買了一本書,剩余:" + books.size());
        sellCondition.signal();  //通知售貨員進書
        lock.unlock();
    }
}
/*
 * 測試類
 */
public class Test {
    public static void main(String[] args) {
        BookStore bookStore = new BookStore();
        Buyer[]  buyers = new Buyer[5];
        Seller  sellers;
        //創建5個買家線程,負責買書
        for(int i = 0; i < 5; i++) {
            buyers[i] = new Buyer(bookStore);
        }
        //創建售貨員線程,負責進書
        sellers = new Seller(bookStore);
        //啟動線程
        sellers.start();
        for(int i = 0; i < 5; i++) {
            buyers[i].start();
        }
    }
}

運行結果:

 

從結果我們可以看到售貨員線程和買家線程是交替運行的,這就是因為兩類線程分別綁定了兩個不同的Condition:buyCondition,sellCondition。從而實現了兩類線程的交替喚醒。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM