Java併發——使用Condition執行緒間通訊
1. Java中執行緒協作的最常見的兩種方式:利用Object.wait()、Object.notify()和使用Condition
(1)複習一下Object.wait()、Object.notify()
在java中,對於任意一個java物件,它都擁有一組定義在java.lang.Object上監視器方法,包括wait(),wait(long timeout),notify(),notifyAll(),這些方法配合synchronized關鍵字一起使用可以實現等待/通知模式。
以前的文章:https://blog.csdn.net/zhm1563550235/article/details/84259542
(2)什麼是Condition介面?
Condition介面也提供了類似Object監視器的方法,通過與Lock配合來實現等待/通知模式。
2. Condition介面
介面Condition把Object的wait和notification方法(包括wait()、notify()、notifyAll())分解到不同的條件物件中。通過把這些條件和任意Lock實現的使用組合起來,起到讓每個物件上具有多重等待集合的作用。這裡Lock取代了同步方法、同步程式碼塊,condition取代了Object的wait、notification方法。
3. Condition宣告的方法
方法名稱 | 描述 |
void await() | 在接收到訊號或被中斷以前,強制呼叫執行緒一直等待。 |
boolean await(long time, TimeUnit unit) | 在接收到訊號、被中斷,或者超過指定的等待時間之前,強制呼叫執行緒一直等待。 同樣是在await()基礎上增加了超時響應,不同的是:
|
long awaitNanos(long nanosTimeout) | 在接收到訊號,被中斷,或者超過指定的等待時間之前,強制呼叫執行緒一直等待。同樣是在await()基礎上增加了超時響應,不同的是: 返回值表示當前剩餘的時間,如果在nanosTimeout之前被喚醒,返回值 = nanosTimeout - 實際消耗的時間,返回值 <= 0表示超時; |
void awaitUninterruptibly() | 在接收到訊號之前,強制當前執行緒一直等待。 |
boolean awaitUntil(Date deadline) | 在接收到訊號、被中斷,或者超過指定的截止時間之前,強制當前的執行緒一直等待。 |
void signal() | 喚醒一個等待中的執行緒。 |
void signalAll() | 喚醒所有等待中的執行緒。 |
4. 獲取Condition
Condition例項實質上被繫結到一個鎖上。一個鎖內部可以有多個Condition,即有多路等待和通知。要為特定 Lock 例項獲得 Condition 例項,請使用其 newCondition() 方法。
Conditon newCondition() 返回用來與當前Lock例項一起使用的Condition例項。
類似於 object.wait()和object.notify()的功能。object.wait()與object.notify()需要結合synchronized使用。Condition需要結合ReentrantLock使用。
5. Condition與迴圈一起使用,防止"虛假喚醒"
在等待Condition時,允許發生"虛假喚醒",這通常作為對基礎平臺語義的讓步。若使用"if(!條件)"則被"虛假喚醒"的執行緒可能繼續執行。所以"while(!條件)"可以防止"虛假喚醒"。建議總是假定這些"虛假喚醒"可能發生,因此總是在一個迴圈中等待。
6. Condition的使用
(1)使用Object的wait()和notify()實現生產者消費者:
public class Test {
private int queueSize = 10;
private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
public static void main(String[] args) {
Test test = new Test();
Producer producer = test.new Producer();
Consumer consumer = test.new Consumer();
producer.start();
consumer.start();
}
class Consumer extends Thread{
@Override
public void run() {
consume();
}
private void consume() {
while(true){
synchronized (queue) {
while(queue.size() == 0){
try {
System.out.println("佇列空,等待資料");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
queue.notify();
}
}
queue.poll(); //每次移走隊首元素
queue.notify();
System.out.println("從佇列取走一個元素,佇列剩餘"+queue.size()+"個元素");
}
}
}
}
class Producer extends Thread{
@Override
public void run() {
produce();
}
private void produce() {
while(true){
synchronized (queue) {
while(queue.size() == queueSize){
try {
System.out.println("佇列滿,等待有空餘空間");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
queue.notify();
}
}
queue.offer(1); //每次插入一個元素
queue.notify();
System.out.println("向佇列取中插入一個元素,佇列剩餘空間:"+(queueSize-queue.size()));
}
}
}
}
}
(2)使用Condition實現消費者生產者
public class Test {
private int queueSize = 10;
private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
public static void main(String[] args) {
Test test = new Test();
Producer producer = test.new Producer();
Consumer consumer = test.new Consumer();
producer.start();
consumer.start();
}
class Consumer extends Thread{
@Override
public void run() {
consume();
}
private void consume() {
while(true){
lock.lock();
try {
while(queue.size() == 0){
try {
System.out.println("佇列空,等待資料");
notEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.poll(); //每次移走隊首元素
notFull.signal();
System.out.println("從佇列取走一個元素,佇列剩餘"+queue.size()+"個元素");
} finally{
lock.unlock();
}
}
}
}
class Producer extends Thread{
@Override
public void run() {
produce();
}
private void produce() {
while(true){
lock.lock();
try {
while(queue.size() == queueSize){
try {
System.out.println("佇列滿,等待有空餘空間");
notFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.offer(1); //每次插入一個元素
notEmpty.signal();
System.out.println("向佇列取中插入一個元素,佇列剩餘空間:"+(queueSize-queue.size()));
} finally{
lock.unlock();
}
}
}
}
}