1.Condition
將 Object
監視器方法(wait()、notify()和notifyAll()
)分解成截然不同的對象,以便通過將這些對象與任意Lock實現組合使用,爲每個對象提供多個等待 set(wait-set)。其中,Lock
替代了 synchronized
方法和語句的使用,Condition
替代了 Object 監視器方法的使用。
條件(也稱爲條件隊列 或條件變量)爲線程提供了一個含義,以便在某個狀態條件現在可能爲 true 的另一個線程通知它之前,一直掛起該線程(即讓其“等待”)。因爲訪問此共享狀態信息發生在不同的線程中,所以它必須受保護,因此要將某種形式的鎖與該條件相關聯。等待提供一個條件的主要屬性是:以原子方式 釋放相關的鎖,並掛起當前線程,就像 Object.wait
做的那樣。
Condition
實例實質上被綁定到一個鎖上。要爲特定Lock
實例獲得 Condition
實例,請使用其 newCondition()方法。作爲一個示例,假定有一個綁定的緩衝區,它支持 put
和 take
方法。如果試圖在空的緩衝區上執行 take
操作,則在某一個項變得可用之前,線程將一直阻塞;如果試圖在滿的緩衝區上執行 put
操作,則在有空間變得可用之前,線程將一直阻塞。我們喜歡在單獨的等待 set 中保存 put
線程和 take
線程,這樣就可以在緩衝區中的項或空間變得可用時利用最佳規劃,一次只通知一個線程。可以使用兩個Condition
實例來做到這一點。
1. 定義消息管道
package com.java.test;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 存儲 生產者消息的通道
* @author jiajie
*
*/
public class MiddlewareChannel2 {
public int init_capacity=0;//初始存儲
public int max_capacity=20;//最大存儲 最大容量值
private Lock lock = new ReentrantLock();
private Condition conumer = lock.newCondition();
private Condition producer = lock.newCondition();
/**
* 消息端產生消息
*
* @param message
*/
public void send() {
//拿到鎖
try {
lock.lock();
//判斷通道是否已滿
if(init_capacity > max_capacity) { //已滿
try {
System.out.println("庫存已滿,生產者等待發送信息...");
//生產者 等待發送消息
producer.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
//通知消費者 消費消息
System.out.println(Thread.currentThread().getName()+":生產消息" +"庫存容量:"+(++init_capacity));
//喚醒所有消費者
conumer.signalAll();
}
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}finally {
lock.unlock();
}
}
/**
* 消息端 消費消息
*/
public void accept() {
try {
lock.lock();
//判斷通道是否有消息
if (init_capacity>0) { //通道有消息
//彈出消息
System.out.println(Thread.currentThread().getName()+":消費消息:"+" 庫存容量:"+(--init_capacity));
//消費完喚醒生產者 生產消息
producer.signalAll();
}else { //通道無消息
try {
System.out.println("庫存不足,等待生產者生產消息...");
//等待消費
conumer.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}finally {
lock.unlock();
}
}
}
2發送端
package com.java.test;
/**
* 生產者
* @author jiajie
*
*/
public class Producer implements Runnable{
private MiddlewareChannel middlewareChannel;
private String threadName;
private String message;
/**
* 構造通道類
* @param middlewareChannel
*/
public Producer(MiddlewareChannel middlewareChannel) {
this.middlewareChannel = middlewareChannel;
}
/**
* 生產消息
*/
@Override
public void run() {
// TODO Auto-generated method stub
// while (true) {
// System.out.println(Thread.currentThread().getName());
// middlewareChannel.send(message);
// }
for (int i = 0; i < 20; i++) {
// System.out.println(Thread.currentThread().getName());
middlewareChannel.send();
}
}
}
2.消費端
package com.java.test;
import javax.sound.midi.MidiChannel;
/**
* 消費者
* @author jiajie
*
*/
public class Conumer implements Runnable{
private MiddlewareChannel middlewareChannel;
public Conumer(MiddlewareChannel middlewareChannel) {
this.middlewareChannel = middlewareChannel;
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
// System.out.println(Thread.currentThread().getName());
middlewareChannel.accept();
}
}
}
3.測試
package com.java.test;
public class ClientTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//創建消息通道
MiddlewareChannel middlewareChannel = new MiddlewareChannel();
//創建消息消費者
Conumer conumer1 = new Conumer(middlewareChannel);
new Thread(conumer1,"消費者1").start();
// //創建消息消費者
// Conumer conumer2 = new Conumer(middlewareChannel);
// new Thread(conumer2, "消費者2").start();
//創建消息生產者1
Producer producer1 = new Producer(middlewareChannel);
new Thread(producer1,"生產者1").start();
// //創建消息生產者2
// Producer producer2 = new Producer(middlewareChannel, "我愛加班");
// new Thread(producer2,"生產者2").start();
}
}