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)