第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

鎖機制之 Condition 接口

1. 前言

本節(jié)內容主要是對 Java 鎖機制之 Condition 接口進行講解,Condition 接口是配合 Lock 接口使用的,我們已經(jīng)學習過 Lock 接口的相關知識,那么接下來對 Condition 接口進行講解。本節(jié)內容的知識點如下:

  • Condition 接口簡介,這是我們認識 Condition 接口的基礎;
  • Condition 接口定義,整體上先了解 Condition 接口所包含的方法,為基礎內容;
  • Condition 接口所提供的方法與 Object 所提供的方法的區(qū)別與聯(lián)系,此部分為本節(jié)的重點之一;
  • Condition 對象的創(chuàng)建方式,這是開始使用 Condition 的前提,需要牢記;
  • Condition 接口的常用方法使用,這是本節(jié)課程的核心內容,掌握 Condition 接口使用方式,也是我們本節(jié)課程的最終目的所在;
  • 使用 ReentrantLock 與 Condition 接口,實現(xiàn)生產者與消費者模式。

2. Condition 接口簡介

任意一個 Java 對象,都擁有一組監(jiān)視器方法(定義在 java.lang.Object 上),主要包括 wait ()、wait (long timeout)、notify () 以及 notifyAll () 方法。這些方法與 synchronized 同步關鍵字配合,可以實現(xiàn)等待 / 通知模式。

定義:Condition 接口也提供了類似 Object 的監(jiān)視器方法,與 Lock 配合可以實現(xiàn)等待 / 通知模式。Condition 可以看做是 Obejct 類的 wait ()、notify ()、notifyAll () 方法的替代品,與 Lock 配合使用。

3. Condition 接口定義

我們看到,從 JDK 的源碼中可以獲悉,Condition 接口包含了如下的方法,對于其中常用的方法,我們在后續(xù)的內容中會有比較詳細的講解。

public interface Condition {
    void await() throws InterruptedException;
    long awaitNanos(long nanosTimeout) throws InterruptedException; 
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    boolean awaitUntil(Date deadline) throws InterruptedException;
    void signal();
    void signalAll();
}

4. Condition 方法與 Object 方法的聯(lián)系與區(qū)別

聯(lián)系 1:都有一組類似的方法.

  • Object 對象監(jiān)視器: Object.wait()、Object.wait(long timeout)、Object.notify()、Object.notifyAll()。
  • Condition 對象: Condition.await()、Condition.awaitNanos(long nanosTimeout)、Condition.signal()、Condition.signalAll()。

聯(lián)系 2:都需要和鎖進行關聯(lián)。

  • Object 對象監(jiān)視器: 需要進入 synchronized 語句塊(進入對象監(jiān)視器)才能調用對象監(jiān)視器的方法。
  • Condition 對象: 需要和一個 Lock 綁定。

區(qū)別

  • Condition 拓展的語義方法,如 awaitUninterruptibly () 等待時忽略中斷方法;
  • 在使用方法時,Object 對象監(jiān)視器是進入 synchronized 語句塊(進入對象監(jiān)視器)后調用 Object.wait ()。而 Condition 對象需要和一個 Lock 綁定,并顯示的調用 lock () 獲取鎖,然后調用 Condition.await ();
  • 從等待隊列數(shù)量看,Object 對象監(jiān)視器是 1 個。而 Condition 對象是多個??梢酝ㄟ^多次調用 lock.newCondition () 返回多個等待隊列。

5. Condition 對象的創(chuàng)建

Condition 對象是由 Lock 對象創(chuàng)建出來的 (Lock.newCondition),換句話說,Condition 是依賴 Lock 對象的。那么我們來看看如果創(chuàng)建 Condition 對象。

此處僅提供示例代碼,后續(xù)我們在進行方法講解時,會有全部的代碼示例,但在學習使用方法之前,我們必須先學會如何創(chuàng)建。

Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();

6. Condition 方法介紹

等待機制方法簡介

  • void await() throws InterruptedException:當前線程進入等待狀態(tài),直到被其它線程的喚醒繼續(xù)執(zhí)行或被中斷;
  • void awaitUninterruptibly():當前線程進入等待狀態(tài),直到被其它線程被喚醒;
  • long awaitNanos(long nanosTimeout) throws InterruptedException:當前線程進入等待狀態(tài),直到被其他線程喚醒或被中斷,或者指定的等待時間結束;nanosTimeout 為超時時間,返回值 = 超時時間 - 實際消耗時間;
  • boolean await(long time, TimeUnit unit) throws InterruptedException:當前線程進入等待狀態(tài),直到被其他線程喚醒或被中斷,或者指定的等待時間結束;與上個方法區(qū)別:可以自己設置時間單位,未超時被喚醒返回 true,超時則返回 false;
  • boolean awaitUntil(Date deadline) throws InterruptedException:當前線程等待狀態(tài),直到被其他線程喚醒或被中斷,或者指定的截止時間結束,截止時間結束前被喚醒,返回 true,否則返回 false。

通知機制方法簡介

  • void signal():喚醒一個線程;
  • void signalAll():喚醒所有線程。

7. ReentrantLock 與 Condition 實現(xiàn)生產者與消費者

非常熟悉的場景設計,這是我們在講解生產者與消費者模型時使用的案例設計,那么此處有細微的修改如下,請學習者進行比照學習,印象更加深刻。

場景修改

  • 創(chuàng)建一個工廠類 ProductFactory,該類包含兩個方法,produce 生產方法和 consume 消費方法(未改變);
  • 對于 produce 方法,當沒有庫存或者庫存達到 10 時,停止生產。為了更便于觀察結果,每生產一個產品,sleep 3000 毫秒(5000 變 3000,調用地址也改變了,具體看代碼);
  • 對于 consume 方法,只要有庫存就進行消費。為了更便于觀察結果,每消費一個產品,sleep 5000 毫秒(sleep 調用地址改變了,具體看代碼);
  • 庫存使用 LinkedList 進行實現(xiàn),此時 LinkedList 即共享數(shù)據(jù)內存(未改變);
  • 創(chuàng)建一個 Producer 生產者類,用于調用 ProductFactory 的 produce 方法。生產過程中,要對每個產品從 0 開始進行編號 (新增 sleep 3000ms);
  • 創(chuàng)建一個 Consumer 消費者類,用于調用 ProductFactory 的 consume 方法 (新增 sleep 5000ms);
  • 創(chuàng)建一個測試類,main 函數(shù)中創(chuàng)建 2 個生產者和 3 個消費者,運行程序進行結果觀察(未改變)。

實例

public class DemoTest {
        public static void main(String[] args) {
            ProductFactory productFactory = new ProductFactory();
            new Thread(new Producer(productFactory),"1號生產者"). start();
            new Thread(new Producer(productFactory),"2號生產者"). start();
            new Thread(new Consumer(productFactory),"1號消費者"). start();
            new Thread(new Consumer(productFactory),"2號消費者"). start();
            new Thread(new Consumer(productFactory),"3號消費者"). start();
        }
}

class ProductFactory {
    private LinkedList<String> products; //根據(jù)需求定義庫存,用 LinkedList 實現(xiàn)
    private int capacity = 10; // 根據(jù)需求:定義最大庫存 10
    private Lock lock = new ReentrantLock(false);
    private Condition p = lock.newCondition();
    private Condition c = lock.newCondition();
    public ProductFactory() {
        products = new LinkedList<String>();
    }
    // 根據(jù)需求:produce 方法創(chuàng)建
    public void produce(String product) {
        try {
            lock.lock();
            while (capacity == products.size()) { //根據(jù)需求:如果達到 10 庫存,停止生產
                try {
                    System.out.println("警告:線程("+Thread.currentThread().getName() + ")準備生產產品,但產品池已滿");
                    p.await(); // 庫存達到 10 ,生產線程進入 wait 狀態(tài)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            products.add(product); //如果沒有到 10 庫存,進行產品添加
            System.out.println("線程("+Thread.currentThread().getName() + ")生產了一件產品:" + product+";當前剩余商品"+products.size()+"個");
            c.signalAll(); //生產了產品,通知消費者線程從 wait 狀態(tài)喚醒,進行消費
        } finally {
            lock.unlock();
        }
    }

    // 根據(jù)需求:consume 方法創(chuàng)建
    public String consume() {
        try {
            lock.lock();
            while (products.size()==0) { //根據(jù)需求:沒有庫存消費者進入wait狀態(tài)
                try {
                    System.out.println("警告:線程("+Thread.currentThread().getName() + ")準備消費產品,但當前沒有產品");
                    c.await(); //庫存為 0 ,無法消費,進入 wait ,等待生產者線程喚醒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            String product = products.remove(0) ; //如果有庫存則消費,并移除消費掉的產品
            System.out.println("線程("+Thread.currentThread().getName() + ")消費了一件產品:" + product+";當前剩余商品"+products.size()+"個");
            p.signalAll();// 通知生產者繼續(xù)生產
            return product;
        } finally {
            lock.unlock();
        }
    }
}

class Producer implements Runnable {
    private ProductFactory productFactory; //關聯(lián)工廠類,調用 produce 方法
    public Producer(ProductFactory productFactory) {
        this.productFactory = productFactory;
    }
    public void run() {
        int i = 0 ; // 根據(jù)需求,對產品進行編號
        while (true) {
            productFactory.produce(String.valueOf(i)); //根據(jù)需求 ,調用 productFactory 的 produce 方法
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
    }
}
class Consumer implements Runnable {
    private ProductFactory productFactory;
    public Consumer(ProductFactory productFactory) {
        this.productFactory = productFactory;
    }
    public void run() {
        while (true) {
            productFactory.consume();
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

結果驗證

線程(1號生產者)生產了一件產品:0;當前剩余商品1個
線程(2號生產者)生產了一件產品:0;當前剩余商品2個
線程(1號消費者)消費了一件產品:0;當前剩余商品1個
線程(2號消費者)消費了一件產品:0;當前剩余商品0個
警告:線程(3號消費者)準備消費產品,但當前沒有產品
線程(2號生產者)生產了一件產品:1;當前剩余商品1個
線程(1號生產者)生產了一件產品:1;當前剩余商品2個
線程(3號消費者)消費了一件產品:1;當前剩余商品1個
線程(2號消費者)消費了一件產品:1;當前剩余商品0個
警告:線程(1號消費者)準備消費產品,但當前沒有產品

8. 小結

本節(jié)內容為主要對 Condition 接口進行了講解,Condition 接口作為 Lock 接口的監(jiān)視器,是非常重要的接口,我們需要非常重視 Condition 接口的學習。

本節(jié)內容最終的目的是使用 Condition 接口和 Lock 配合實現(xiàn)案例,核心內容即為 Condition 接口的使用,請翻看生產者與消費者一節(jié),對比進行學習。