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

鎖機(jī)制之 Condition 接口

1. 前言

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

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

2. Condition 接口簡(jiǎn)介

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

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

3. Condition 接口定義

我們看到,從 JDK 的源碼中可以獲悉,Condition 接口包含了如下的方法,對(duì)于其中常用的方法,我們?cè)诤罄m(xù)的內(nèi)容中會(huì)有比較詳細(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 對(duì)象監(jiān)視器: Object.wait()、Object.wait(long timeout)、Object.notify()、Object.notifyAll()。
  • Condition 對(duì)象: Condition.await()、Condition.awaitNanos(long nanosTimeout)、Condition.signal()、Condition.signalAll()。

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

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

區(qū)別

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

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

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

此處僅提供示例代碼,后續(xù)我們?cè)谶M(jìn)行方法講解時(shí),會(huì)有全部的代碼示例,但在學(xué)習(xí)使用方法之前,我們必須先學(xué)會(huì)如何創(chuàng)建。

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

6. Condition 方法介紹

等待機(jī)制方法簡(jiǎn)介

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

通知機(jī)制方法簡(jiǎn)介

  • void signal():?jiǎn)拘岩粋€(gè)線程;
  • void signalAll():?jiǎn)拘阉芯€程。

7. ReentrantLock 與 Condition 實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者

非常熟悉的場(chǎng)景設(shè)計(jì),這是我們?cè)谥v解生產(chǎn)者與消費(fèi)者模型時(shí)使用的案例設(shè)計(jì),那么此處有細(xì)微的修改如下,請(qǐng)學(xué)習(xí)者進(jìn)行比照學(xué)習(xí),印象更加深刻。

場(chǎng)景修改

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

實(shí)例

public class DemoTest {
        public static void main(String[] args) {
            ProductFactory productFactory = new ProductFactory();
            new Thread(new Producer(productFactory),"1號(hào)生產(chǎn)者"). start();
            new Thread(new Producer(productFactory),"2號(hào)生產(chǎn)者"). start();
            new Thread(new Consumer(productFactory),"1號(hào)消費(fèi)者"). start();
            new Thread(new Consumer(productFactory),"2號(hào)消費(fèi)者"). start();
            new Thread(new Consumer(productFactory),"3號(hào)消費(fèi)者"). start();
        }
}

class ProductFactory {
    private LinkedList<String> products; //根據(jù)需求定義庫存,用 LinkedList 實(shí)現(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ù)需求:如果達(dá)到 10 庫存,停止生產(chǎn)
                try {
                    System.out.println("警告:線程("+Thread.currentThread().getName() + ")準(zhǔn)備生產(chǎn)產(chǎn)品,但產(chǎn)品池已滿");
                    p.await(); // 庫存達(dá)到 10 ,生產(chǎn)線程進(jìn)入 wait 狀態(tài)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            products.add(product); //如果沒有到 10 庫存,進(jìn)行產(chǎn)品添加
            System.out.println("線程("+Thread.currentThread().getName() + ")生產(chǎn)了一件產(chǎn)品:" + product+";當(dāng)前剩余商品"+products.size()+"個(gè)");
            c.signalAll(); //生產(chǎn)了產(chǎn)品,通知消費(fèi)者線程從 wait 狀態(tài)喚醒,進(jìn)行消費(fèi)
        } finally {
            lock.unlock();
        }
    }

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

class Producer implements Runnable {
    private ProductFactory productFactory; //關(guān)聯(lián)工廠類,調(diào)用 produce 方法
    public Producer(ProductFactory productFactory) {
        this.productFactory = productFactory;
    }
    public void run() {
        int i = 0 ; // 根據(jù)需求,對(duì)產(chǎn)品進(jìn)行編號(hào)
        while (true) {
            productFactory.produce(String.valueOf(i)); //根據(jù)需求 ,調(diào)用 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();
            }
        }
    }
}

結(jié)果驗(yàn)證

線程(1號(hào)生產(chǎn)者)生產(chǎn)了一件產(chǎn)品:0;當(dāng)前剩余商品1個(gè)
線程(2號(hào)生產(chǎn)者)生產(chǎn)了一件產(chǎn)品:0;當(dāng)前剩余商品2個(gè)
線程(1號(hào)消費(fèi)者)消費(fèi)了一件產(chǎn)品:0;當(dāng)前剩余商品1個(gè)
線程(2號(hào)消費(fèi)者)消費(fèi)了一件產(chǎn)品:0;當(dāng)前剩余商品0個(gè)
警告:線程(3號(hào)消費(fèi)者)準(zhǔn)備消費(fèi)產(chǎn)品,但當(dāng)前沒有產(chǎn)品
線程(2號(hào)生產(chǎn)者)生產(chǎn)了一件產(chǎn)品:1;當(dāng)前剩余商品1個(gè)
線程(1號(hào)生產(chǎn)者)生產(chǎn)了一件產(chǎn)品:1;當(dāng)前剩余商品2個(gè)
線程(3號(hào)消費(fèi)者)消費(fèi)了一件產(chǎn)品:1;當(dāng)前剩余商品1個(gè)
線程(2號(hào)消費(fèi)者)消費(fèi)了一件產(chǎn)品:1;當(dāng)前剩余商品0個(gè)
警告:線程(1號(hào)消費(fèi)者)準(zhǔn)備消費(fèi)產(chǎn)品,但當(dāng)前沒有產(chǎn)品

8. 小結(jié)

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

本節(jié)內(nèi)容最終的目的是使用 Condition 接口和 Lock 配合實(shí)現(xiàn)案例,核心內(nèi)容即為 Condition 接口的使用,請(qǐng)翻看生產(chǎn)者與消費(fèi)者一節(jié),對(duì)比進(jìn)行學(xué)習(xí)。