談到阻塞隊列需要談到以往的lock中的await和signel,以往線程的狀態需要我們手動修改來完成線程間的調度,此時BlockingQueue阻塞隊列橫空出世,即線程狀態的掛起和喚醒狀態都由該隊列內部完成,你用即可,該隊列在多線程場景下,可以很好的實現生產和消費的模式,其實消息中間件底層用的就是該隊列。
BlockingQueue核心的方法就是offer和poll,即放和拿,不傳參意爲拿不到或放不進消息我就一種等,直到拿到消息,要是傳參,即我也是有限度的,等了那麼久還沒放入或拿到那我就停了。
package com.reentralock;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
class MySource{//資源類
private volatile boolean flag = true;//全網開關
private AtomicInteger atomicInteger =new AtomicInteger();
private BlockingQueue<String> queue = null;//留着給別人用的隊列,口子要大,傳它的子類全可以
public MySource(BlockingQueue<String> queue) {
super();
this.queue = queue;
System.out.println(queue.getClass().getName());//日誌打印細粒度
}
public void myProduct() throws Exception{
String data = "";
boolean result;
//1.判斷
while(flag){
data = atomicInteger.incrementAndGet()+"";
result = queue.offer(data, 2, TimeUnit.SECONDS);//2s加不進去不加了
if(result){
System.out.println("生產cake"+data+"成功");
}else{
System.out.println("生產cake"+data+"失敗");
}
TimeUnit.SECONDS.sleep(1);//生產間隔1s
}
System.out.println("boss叫停,別再生產了!");
}
public void myConsumer() throws Exception{
String data = "";
//1.判斷
while(flag){
data = queue.poll(2, TimeUnit.SECONDS);//兩秒鐘拿不到,我就不拿了
if(null == data || "".equals(data)){
System.out.println("隊列中無cake可消費");
flag = false;
System.out.println("2s未拿到cake,停止拿");
return;//跳出方法
}else{
System.out.println("消費cake"+data+"成功");
}
}
System.out.println("boss叫停,別再生產了!");
}
public void stop(){//boss讓你停 你就停
flag = false;
}
}
/**
* 隊列高級版,阻塞隊列將掛起、喚醒 內部實現,你用即可
*
* 模仿場景,多線程下,只需一個標誌位,控制整個消費和生產的實現,消費者和生產者的來源於去處需要隊列暫存
* 多線程下標配:Atomic、BlockQueue、CAS、Volatile =abcv
*
* 多線程
* 上聯:線程操作資源類
* 下聯:判斷幹活再通知(注意虛假喚醒)= 針對lock而言
* 橫批:BlockQueue屬頂級
*
* @author 英俊
*
*/
public class BlockQueueDemo {
public static void main(String[] args) {
MySource mySource =new MySource(new ArrayBlockingQueue<>(10));
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 生產線程啓動");
try {
mySource.myProduct();
} catch (Exception e) {
e.printStackTrace();
}
}, "product").start();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 消費線程啓動");
try {
mySource.myConsumer();
} catch (Exception e) {
e.printStackTrace();
}
}, "consumer").start();
try {
TimeUnit.SECONDS.sleep(5);
System.out.println("boss 5s叫停!!");
mySource.stop();//5s main主線程叫停!!
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
放心:一直poll拿不到消息,不會佔用cpu資源。