JAVA多線程(十六)Java多線程之Condition對象

1.JAVA多線程(十六)Java多線程之Condition對象

1.1 什麼是Condition?

   Condition是在java 1.5中才出現的,它用來替代傳統的Object的wait()、notify()實現線程間的協作,相比使用Object的wait()、notify(),使用Condition的await()、signal()這種方式實現線程間協作更加安全和高效。因此通常來說比較推薦使用Condition,阻塞隊列實際上是使用了Condition來模擬線程間協作。

   我們使用synchronized來控制同步,配合Object的wait()、notify()系列方法可以實現等待/通知模式。在Java SE5後,Java提供了Lock接口,相對於Synchronized而言,Lock提供了條件Condition,對線程的等待、喚醒操作更加詳細和靈活。下圖是Condition與Object的監視器方法的對比(摘自《Java併發編程的藝術》)
在這裏插入圖片描述

1.2 Condition使用樣例

package com.yuanxw.chapter16;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample {
    // 定義【重入鎖】非公平鎖
    private static final ReentrantLock REENTRANT_LOCK = new ReentrantLock();
    // 獲得Condition實例
    private static final Condition CONDITION = REENTRANT_LOCK.newCondition();
    // volatile:內存可見性關鍵字,默認爲沒有生產,可以進行生產
    private static volatile boolean isProducted = false;
    // 生產數量
    private static int num = 0;

    /**
     * 生產方法
     */
    public static void produce() {
        try {
            // 加鎖
            REENTRANT_LOCK.lock();
            while (isProducted) {
                CONDITION.await();
            }
            // 生產消息數量 + 1
            num++;
            // 設置爲已經生產消息
            isProducted = true;
            // 通知消費者,可以進行消費
            CONDITION.signalAll();
            System.out.println(String.format("線程【%s】,生產消息>>【%s】", Thread.currentThread().getName(), num));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解鎖
            REENTRANT_LOCK.unlock();
        }
    }

    /**
     * 消息方法
     */
    public static void consumer() {
        // 加鎖
        try {
            REENTRANT_LOCK.lock();
            // 如果已經生產,那麼消費者消費
            while (!isProducted) {
                CONDITION.await();
            }
            System.out.println(String.format("線程【%s】,消費消息<<<<【%s】", Thread.currentThread().getName(), num));
            // 設置標記:未生產
            isProducted = false;
            // 通知生產者已經消費
            CONDITION.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            REENTRANT_LOCK.unlock();
        }
    }

    public static void main(String[] args) {
        // 創建兩個生產者線程分別爲:Produce1、Produce2
        Arrays.asList("Produce1", "Produce2").forEach(produceName -> {
            new Thread(() -> {
                while (true) {
                    ConditionExample.produce();
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },produceName).start();
        });

        // 創建三個生產者線程分別爲:Consumer1、Consumer2、Consumer3
        Arrays.asList("Consumer1", "Consumer2", "Consumer3").forEach(consumerName -> {
            new Thread(() -> {
                while (true) {
                    ConditionExample.consumer();
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },consumerName).start();
        });
    }
}

執行結果:

線程【Produce1】,生產消息>>【1】
線程【Consumer1】,消費消息<<<<【1】
線程【Produce2】,生產消息>>【2】
線程【Consumer2】,消費消息<<<<【2】
線程【Produce1】,生產消息>>【3】
線程【Consumer3】,消費消息<<<<【3】
線程【Produce2】,生產消息>>【4】
線程【Consumer1】,消費消息<<<<【4】
線程【Produce1】,生產消息>>【5】
線程【Consumer2】,消費消息<<<<【5】
線程【Produce2】,生產消息>>【6】
線程【Consumer1】,消費消息<<<<【6】
線程【Produce1】,生產消息>>【7】
線程【Consumer3】,消費消息<<<<【7】
線程【Produce2】,生產消息>>【8】
線程【Consumer1】,消費消息<<<<【8】
線程【Produce2】,生產消息>>【9】
線程【Consumer2】,消費消息<<<<【9】
線程【Produce1】,生產消息>>【10】
線程【Consumer1】,消費消息<<<<【10】

    – 以上爲《JAVA多線程(十六)Java多線程之Condition對象》,如有不當之處請指出,我後續逐步完善更正,大家共同提高。謝謝大家對我的關注。

——厚積薄發(yuanxw)

發佈了125 篇原創文章 · 獲贊 166 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章