1.队列+阻塞队列
(1)阻塞队列,顾名思义,首先它是一个队列,而一个阻塞队列在数据结构中所起到的作用大致如下图所示:
当阻塞队列为空的时,从队列中获取元素的操作将会被阻塞。
当阻塞队列是满的时,往队列中增加元素的操作将会被阻塞。
试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往队列中插入新的元素。
同样,试图往已满的阻塞队列中添加新的元素的线程将会被阻塞,直到其他线程从队列中移除一个或多个元素或者完全清空队列后是队列重新变的空闲起来并后续新增。
2.为什么用?有什么好处
在多线程领域:所有阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会被自动唤醒。
为什么需要BlockingQueue
好处是我们不需要关心什么时候需要阻塞线程,什么时候唤醒线程,因为这一切都被BlockingQueue一手包办了
在concurcent包发布以前,在多线程环境中,我们每个程序员都必须去自己控制这个细节,尤其还要兼顾效率和线程安全,而这会给我们程序带来不小的复杂度。
3.架构梳理+种类分析
(1)ArrayBlockingQueue:有数组结构组成的有界阻塞队列
(2)LinkedBlockingQueue:有链表结构组成的有界(大小默认值为Integer.MAX_VALUE=2147483647)阻塞队列
(3)SynchronousQueue:不存储元素的阻塞队列,也及单个元素的队列
(4)PriorityBlockingQueue:支持优先级排序的无界阻塞队列
(5)DelayQueue:使用优先级队列实现的延迟无界阻塞队列
(6)LinkedTransferQueue:由链表结构组成的无界阻塞队列
(7)LinkedBlockingDeque:由链表结构组成的双向无界阻塞队列
案例
package register;
import java.util.Collection;
import java.util.Queue;
import java.util.concurrent.*;
/**
* ArrayBlockingQueue:是一个基于数组的有界阻塞队列,次队列按FIFO(先进先出)的原则对元素进行排序
* LinkedBlockingQueue:一个基于链表结构的阻塞队列,次队列按照FIFO(先进先出)排序元素,吞吐量通常要高于ArrayBlockingQueue
* SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于
*
*
* 阻塞队列
*
*/
public class BlockingQueueDemo {
public static void main(String[] args) {
BlockingQueue<String> blockingQueue=new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"\t put 1");
blockingQueue.put("1");
System.out.println(Thread.currentThread().getName()+"\t put 2");
blockingQueue.put("2");
System.out.println(Thread.currentThread().getName()+"\t put 3");
blockingQueue.put("3");
}catch (Exception e){
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try {
try{TimeUnit.SECONDS.sleep(5);}catch (Exception e){e.printStackTrace();}
System.out.println(Thread.currentThread().getName()+"\t "+blockingQueue.take());
try{TimeUnit.SECONDS.sleep(5);}catch (Exception e){e.printStackTrace();}
System.out.println(Thread.currentThread().getName()+"\t "+blockingQueue.take());
try{TimeUnit.SECONDS.sleep(5);}catch (Exception e){e.printStackTrace();}
System.out.println(Thread.currentThread().getName()+"\t "+blockingQueue.take());
}catch (Exception e){
e.printStackTrace();
}
},"t2").start();
}
}
//输出
t1 put 1
t2 get 1
t1 put 2
t2 get 2
t1 put 3
t2 get 3
4.BlockingQueue核心方法
5.用在哪里
(1)生产者消费者模式
// 传统版
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ShareData{//资源类
private int number=0;
private Lock lock=new ReentrantLock();
private Condition condition=lock.newCondition();
//加法
public void increment() throws Exception{
lock.lock();
try {
// 1.判断
while (number!=0){
//等待,不能生产
condition.await();
}
//干活
number++;
System.out.println(Thread.currentThread().getName()+"\t "+number);
//通知唤醒
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//减法
public void decrement() throws Exception{
lock.lock();
try {
// 1.判断
while (number==0){
//等待,不能生产
condition.await();
}
//干活
number--;
System.out.println(Thread.currentThread().getName()+"\t "+number);
//通知唤醒
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
/**
* 题目:一个初始值为0的变量,两个线程交替操作,一个加1一个减1,来5轮
* 线程 操作 资源类
* 干活 判断 通知
* 防止虚假唤醒机制
*/
public class ProdConsumer_TraditionDemo {
public static void main(String[] args) {
ShareData shareData=new ShareData();
new Thread(()->{
for (int i = 1; i <=5 ; i++) {
try {
shareData.increment();
} catch (Exception e) {
e.printStackTrace();
}
}
},"t1").start();
new Thread(()->{
for (int i = 1; i <=5 ; i++) {
try {
shareData.decrement();
} catch (Exception e) {
e.printStackTrace();
}
}
},"t2").start();
}
}
//输出信息
t1 1
t2 0
t1 1
t2 0
t1 1
t2 0
t1 1
t2 0
t1 1
t2 0
//阻塞队列版
package register;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
class MyResource {
/**
* 默认开启 进行生产消费的交互
*/
private volatile boolean flag = true;
/**
* 默认值是0
*/
private AtomicInteger atomicInteger = new AtomicInteger();
private BlockingQueue<String> blockingQueue = null;
public MyResource(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
System.out.println(blockingQueue.getClass().getName());
}
public void myProd() throws Exception {
String data = null;
boolean returnValue;
while (flag) {
data = atomicInteger.incrementAndGet() + "";
returnValue = blockingQueue.offer(data, 2L, TimeUnit.SECONDS);
if (returnValue) {
System.out.println(Thread.currentThread().getName() + "\t 插入队列数据" + data + "成功");
} else {
System.out.println(Thread.currentThread().getName() + "\t 插入队列数据" + data + "失败");
}
TimeUnit.SECONDS.sleep(1);
}
System.out.println(Thread.currentThread().getName() + "\t 停止 表示 flag" + flag);
}
public void myConsumer() throws Exception {
String result = null;
while (flag) {
result = blockingQueue.poll(2L, TimeUnit.SECONDS);
if(null==result||"".equalsIgnoreCase(result)){
flag=false;
System.out.println(Thread.currentThread().getName()+"\t"+"超过2m没有取到 消费退出");
System.out.println();
System.out.println();
return;
}
System.out.println(Thread.currentThread().getName() + "消费队列" + result + "成功");
}
}
public void stop() throws Exception{
flag=false;
}
}
public class ProdConsumerBlockQueueDemo {
public static void main(String[] args) throws Exception {
MyResource myResource = new MyResource(new ArrayBlockingQueue<>(10));
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t生产线程启动");
try {
myResource.myProd();
} catch (Exception e) {
e.printStackTrace();
}
},"Prod").start();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t消费线程启动");
try {
myResource.myConsumer();
} catch (Exception e) {
e.printStackTrace();
}
},"consumer").start();
try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println();
System.out.println();
System.out.println();
System.out.println("时间到,停止活动");
myResource.stop();
}
}