1.队列

  • 队列是一种数据结构.它有两个基本操作:在队列尾部加入一个元素,和从队列头部移除一个元素(注意不要弄混队列的头部和尾部)就是说,队列以一种先进先出的方式管理数据,如果你试图向一个 已经满了的阻塞队列中添加一个元素或者是从一个空的阻塞队列中移除一个元索,将导致线程阻塞.

  • 在多线程进行合作时,阻塞队列是很有用的工具。工作者线程可以定期地把中间结果存到阻塞队列中而其他工作者线程把中间结果取出并在将来修改它们。队列会自动平衡负载。如果第一个线程集运行得比第二个慢,则第二个 线程集在等待结果时就会阻塞。如果第一个线程集运行得快,那么它将等待第二个线程集赶上来.说白了,就是先进先出,线程安全!

  • java中并发队列都是在java.util.concurrent并发包下的,Queue接口与List、Set同一级别,都是继承了Collection接口

2.实现一个简单的并发队列

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; /**
* @author QiuQiu&LL
* @version 1.0
*/
public class MyQueue {
//元素集合
private LinkedList<Object> list = new LinkedList<Object>();
//计数器(同步),判断集合元素数量
private AtomicInteger count = new AtomicInteger();
//集合上限与下限,final必须指定初值
private final int minSize = 0;
private final int maxSize; //构造器指定最大值
public MyQueue(int maxSize) {
this.maxSize = maxSize;
} //初始化对象,用于加锁,也可直接用this
private Object lock = new Object(); /**
* put方法:往集合中添加元素,如果集合元素已满,则此线程阻塞,直到有空间再继续
*
* @param obj
*/
public void put(Object obj) {
synchronized (lock) {
while (count.get() == this.maxSize) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(obj);
//计数器加一
count.incrementAndGet();
System.out.println("放入元素:" + obj);
//唤醒另一个线程,(处理极端情况:集合一开始就是空,此时take线程会一直等待)
lock.notify();
}
} /**
* take方法:从元素中取数据,如果集合为空,则线程阻塞,直到集合不为空再继续
*
* @return
*/
public Object take() {
Object result = null;
synchronized (lock) {
while (count.get() == this.minSize) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//移除第一个
result = list.removeFirst();
//计数器减一
count.decrementAndGet();
System.out.println("拿走元素:" + result);
//唤醒另一个线程,(处理极端情况:集合一开始就是满的,此时put线程会一直等待)
lock.notify();
}
return result;
} public int getSize() {
return this.count.get();
} public static void main(String[] args) {
//创建集合容器
MyQueue queue = new MyQueue(5);
queue.put("1");
queue.put("2");
queue.put("3");
queue.put("4");
queue.put("5");
System.out.println("当前容器长度为:" + queue.getSize());
Thread t1 = new Thread(() -> {
queue.put("6");
queue.put("7");
// 队列满了,他将会一直等待
queue.put("8");
}, "t1");
Thread t2 = new Thread(() -> {
Object take1 = queue.take();
Object take2 = queue.take();
System.out.println("take1 = " + take1 + "==== take2 = " + take2);
}, "t2");
//测试极端情况,两秒钟后再执行另一个线程,会阻塞等待另一个线程take
t1.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}

3.JDK中并发队列提供了两种实现,一种是高性能队列ConcurrentLinkedQueue,一种是阻塞队列BlockingQueue,两种都继承自Queue

(1)ConcurrentLinkedQueue

import java.util.concurrent.ConcurrentLinkedQueue;

/**
* @author QiuQiu&LL
* @version 1.0
*/
public class ConcurrentLinkedQueueDemo {
public static void main(String[] args) {
ConcurrentLinkedQueue clq = new ConcurrentLinkedQueue();
clq.add(1);
clq.add(2);
clq.add(3);
clq.add(4); // 获取队头元素,并删除
Object poll = clq.poll();
System.out.println("poll = " + poll);
// 获取队头元素,不删除
Object peek = clq.peek();
System.out.println("peek = " + peek); System.out.println("clq = " + clq);
}
}

(2) BlockingQueue

  • blockingQueue主要有5中实现,具体如下

ArrayBlockingQueue

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit; /**
* @author QiuQiu&LL
* @version 1.0
*/
public class ArrayBlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<>(2);
// 添加一个元素
abq.add(1);//add :添加元素,如果BlockingQueue可以容纳,则返回true,否则抛异常,支持添加集合
boolean offerIsSuccess = abq.offer(2);//offer: 如果可能的话,添加元素,即如果BlockingQueue可以容纳,则返回true,否则返回false,支持设置超时时间
System.out.println("offerIsSuccess = " + offerIsSuccess);
//设置超时,如果超过时间就不添加,返回false,
// abq.offer(3, 2, TimeUnit.SECONDS);
//put 添加元素,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续
// abq.put(4);
new Thread(() -> {
//poll 取走头部元素,若不能立即取出,则可以等time参数规定的时间,取不到时返回null,支持设置超时时间
Integer poll = abq.poll();
System.out.println("poll = " + poll);
});
abq.poll(2,TimeUnit.SECONDS);//两秒取不到返回null
abq.offer(3, 2, TimeUnit.SECONDS);
//take() 取走头部元素,若BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止
abq.take();
//取出头部元素,但不删除
abq.element();
List drain=new ArrayList();
//一次性从BlockingQueue获取所有可用的数据对象(还可以指定获取数据的个数),通过该方法,可以提升获取数据效率;不需要多次分批加锁或释放锁。
int to = abq.drainTo(drain);
System.out.println("to = " + to);
System.out.println("drain = " + drain);
List list=new ArrayList();
abq.drainTo(list,2);//将队列中两个元素取到list中,取走后队列中就没有取走的元素
System.out.println(list); //[a,b]
System.out.println(abq); //[]
}
}

ArrayBlockingQueue

import java.util.concurrent.LinkedBlockingQueue;

/**
* @author QiuQiu&LL
* @version 1.0
*/
public class LinkedBlockingQueueDemo {
public static void main(String[] args) {
//可指定容量,也可不指定
LinkedBlockingQueue<String> lbq = new LinkedBlockingQueue<>();
lbq.add("a");
lbq.add("b");
lbq.add("c");
//API与ArrayBlockingQueue相同
//是否包含
System.out.println(lbq.contains("a"));
//移除头部元素或者指定元素 remove("a")
System.out.println(lbq.remove());
//转数组
Object[] array = lbq.toArray();
//element 取出头部元素,但不删除
System.out.println(lbq.element());
System.out.println(lbq.element()); System.out.println("array = " + array);
}
}

SynchronousQueue

import java.util.concurrent.SynchronousQueue;

/**
* @author QiuQiu&LL
* @version 1.0
*/
public class SynchronousQueueDemo {
public static void main(String[] args) {
SynchronousQueue<String> sq=new SynchronousQueue<String>();
// iterator() 永远返回空,因为里面没东西。
// peek() 永远返回null
/**
* isEmpty()永远是true。
* remainingCapacity() 永远是0。
* remove()和removeAll() 永远是false。
*/
new Thread(()->{
try {
//取出并且remove掉queue里的element(认为是在queue里的。。。),取不到东西他会一直等。
System.out.println(sq.take());
} catch (InterruptedException e) {
e.printStackTrace();
} }).start();
new Thread(()->{
try {
//offer() 往queue里放一个element后立即返回,
//如果碰巧这个element被另一个thread取走了,offer方法返回true,认为offer成功;否则返回false
//true ,上面take线程一直在等,
////下面刚offer进去就被拿走了,返回true,如果offer线程先执行,则返回false
System.out.println(sq.offer("b")); } catch (Exception e) {
e.printStackTrace();
} }).start();
new Thread(()->{
try {
//往queue放进去一个element以后就一直wait直到有其他thread进来把这个element取走
sq.put("a");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}

DelayQueue

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit; //网民
public class Netizen implements Delayed {
//身份证
private String ID;
//名字
private String name;
//上网截止时间
private long playTime; //比较优先级,时间最短的优先
@Override
public int compareTo(Delayed o) {
Netizen netizen = (Netizen) o;
return this.getDelay(TimeUnit.SECONDS) - o.getDelay(TimeUnit.SECONDS) > 0 ? 1 : 0;
} public Netizen(String iD, String name, long playTime) {
ID = iD;
this.name = name;
this.playTime = playTime;
} //获取上网时长,即延时时长
@Override
public long getDelay(TimeUnit unit) {
//上网截止时间减去现在当前时间=时长
return this.playTime - System.currentTimeMillis();
} public String getID() {
return ID;
} public void setID(String ID) {
this.ID = ID;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public long getPlayTime() {
return playTime;
} public void setPlayTime(long playTime) {
this.playTime = playTime;
}
}
import java.util.concurrent.DelayQueue;

//网吧
public class InternetBar implements Runnable {
//网民队列,使用延时队列
private DelayQueue<Netizen> dq = new DelayQueue<Netizen>(); //上网
public void startPlay(String id, String name, Integer money) {
//截止时间= 钱数*时间+当前时间(1块钱1秒)
Netizen netizen = new Netizen(id, name, 1000 * money + System.currentTimeMillis());
System.out.println(name + "开始上网计费......");
dq.add(netizen);
} //时间到下机
public void endTime(Netizen netizen) {
System.out.println(netizen.getName() + "余额用完,下机");
} @Override
public void run() {
//线程,监控每个网民上网时长
while (true) {
try {
//除非时间到.否则会一直等待,直到取出这个元素为止
Netizen netizen = dq.take();
endTime(netizen);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
//新建一个网吧
InternetBar internetBar = new InternetBar();
//来了三个网民上网
internetBar.startPlay("001", "qiuqiu", 3);
internetBar.startPlay("002", "ll", 7);
internetBar.startPlay("003", "QIUQIU&LL", 5);
Thread t1 = new Thread(internetBar);
t1.start();
}
}

4.案例1

import java.util.ArrayDeque;
import java.util.Queue; /**
* @author QiuQiu&LL
* @version 1.0
* 模拟银行办理业务员
*/
public class MyQueueDemo {
public static void main(String[] args) {
Queue<Request> que = new ArrayDeque<Request>();
//模拟排队情况
for (int i = 0; i < 10; i++) {
final int num = i;
que.offer(new Request() {
//应用匿名内部类对象只能访问 final 修饰的变量
@Override
public void deposit() {
System.out.println("第" + num + "个人,办理存款业务,存款额度为:" + (Math.random() * 10000));
}
});
}
dealWith(que);
} //处理业务
public static void dealWith(Queue<Request> que) {
Request req = null;
while (null != (req = que.poll())) {
req.deposit();
}
}
} interface Request {
//存款
void deposit();
}

5.案例2

import java.util.ArrayDeque;
import java.util.Deque; /**
* 使用队列实现自定义堆栈
* 1、弹
* 2、压
* 3、获取头
*/
public class MyStack<E> {
//容器
private Deque<E> container = new ArrayDeque<E>();
//容量
private int cap; public MyStack(int cap) {
super();
this.cap = cap;
} //压栈
public boolean push(E e) {
if (container.size() + 1 > cap) {
return false;
}
return container.offerLast(e);
} //弹栈
public E pop() {
return container.pollLast();
} //获取
public E peek() {
return container.peekLast();
} public int size() {
return this.container.size();
}
} //测试自定义堆栈
public class MyStockDemo {
/**
* @param args
*/
public static void main(String[] args) {
MyStack<String> backHistory = new MyStack<String>(3);
backHistory.push("www.baidu.com");
backHistory.push("www.google.com");
backHistory.push("www.sina.com");
backHistory.push("www.bjsxt.cn");
System.out.println("大小:" + backHistory.size()); //遍历
String item = null;
while (null != (item = backHistory.pop())) {
System.out.println(item);
}
}
}

Java中的并发队列的更多相关文章

  1. 聊聊并发(七)——Java中的阻塞队列

    3. 阻塞队列的实现原理 聊聊并发(七)--Java中的阻塞队列 作者 方腾飞 发布于 2013年12月18日 | ArchSummit全球架构师峰会(北京站)2016年12月02-03日举办,了解更 ...

  2. Java中的阻塞队列(BlockingQueue)

    1. 什么是阻塞队列 阻塞队列(BlockingQueue)是 Java 5 并发新特性中的内容,阻塞队列的接口是 java.util.concurrent.BlockingQueue,它提供了两个附 ...

  3. 多线程编程学习六(Java 中的阻塞队列).

    介绍 阻塞队列(BlockingQueue)是指当队列满时,队列会阻塞插入元素的线程,直到队列不满:当队列空时,队列会阻塞获得元素的线程,直到队列变非空.阻塞队列就是生产者用来存放元素.消费者用来获取 ...

  4. JUC之Java中的阻塞队列及其实现原理

    在文章线程池实现原理 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中介绍了线程池的组成部分,其中一个组成部分就是阻塞队列.那么JAVA中的阻塞队列如何实现的呢? 阻塞队列,关键字是阻塞 ...

  5. Java中的阻塞队列-ArrayBlockingQueue(一)

    最近在看一些java基础的东西,看到了队列这章,打算对复习的一些知识点做一个笔记,也算是对自己思路的一个整理,本章先聊聊java中的阻塞队列 参考文章: http://ifeve.com/java-b ...

  6. Java 中的并发工具类

    Java 中的并发工具类 CountDownLatch public class JoinCountDownLatchTest { public static void main(String[] a ...

  7. 阻塞队列一——java中的阻塞队列

    目录 阻塞队列简介:介绍阻塞队列的特性与应用场景 java中的阻塞队列:介绍java中实现的供开发者使用的阻塞队列 BlockQueue中方法:介绍阻塞队列的API接口 阻塞队列的实现原理:具体的例子 ...

  8. JAVA中关于并发的一些理解

    一,JAVA线程是如何实现的? 同步,涉及到多线程操作,那在JAVA中线程是如何实现的呢? 操作系统中讲到,线程的实现(线程模型)主要有三种方式: ①使用内核线程实现 ②使用用户线程实现 ③使用用户线 ...

  9. JAVA多线程(二) 并发队列和阻塞队列

    github代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-service/ ...

  10. Java中的并发库学习总结

    我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便.而当针对高质量Java ...

随机推荐

  1. 掌握Go的运行时:从编译到执行

    讲解Go语言从编译到执行全周期流程,每一部分都会包含丰富的技术细节和实际的代码示例,帮助大家理解. 关注微信公众号[TechLeadCloud],分享互联网架构.云服务技术的全维度知识.作者拥有10+ ...

  2. 10分钟理解契约测试及如何在C#中实现

    在软件开发中,确保微服务和API的可靠性和稳定性非常重要. 随着应用程序变得越来越复杂,对强大的测试策略的需求也越来越大,这些策略可以帮助团队在不牺牲敏捷性的情况下交付高质量的代码. 近年来获得广泛关 ...

  3. 前端远程调试方案 Chii 的使用经验分享

    前端远程调试方案 Chii 的使用经验分享 Chii 是与 weinre 一样的远程调试工具 ,主要是将 web inspector 替换为最新的 chrome devtools frontend 监 ...

  4. Python Flask 上下文管理源码分析

    Python Flask 上下文管理源码分析 前言 Flask 上下文管理可以说是 Flask 非常具有特色的设计,它总共可分为 2 个大的方向: 应用上下文管理:通过 current_app 即可拿 ...

  5. RK3568开发笔记(十一):开发版buildroot固件移植一个ffmpeg播放rtsp的播放器Demo

    前言   目标开发任务还有个功能,就是播放rtsp摄像头,当然为了更好的坐这个个,我们必须支持rtsp播放失败之后重新尝试,比如5s重新尝试打开一次,从而保障联网后重新打开,然后达成这个功能.   D ...

  6. Python 有趣的模块之pynupt——通过pynput控制鼠标和键盘

    写在前面 Python中有许多有趣和强大的模块,其中一个非常有趣的模块就是pynupt.pynupt是基于pynput模块的一个封装,用于控制鼠标和键盘.它可以实现自动化操作和游戏外挂等功能. 本文将 ...

  7. Python中的可迭代对象和迭代器

    1.可迭代对象 1.1.可迭代对象概念 可迭代对象,最直观的感觉就是可以使用for来循环迭代每一个元素.例如Python内置的类型:str.list.tuple.dict等类型的对象,都是可迭代对象. ...

  8. 前端三件套系例之BootStrap—— BootStrap组件、BootStrap插件

    文章目录 1 BootStrap组件 1 Glyphicons 字体图标 2 下拉菜单 2.1 基本使用 2.2 对齐 2.3 标题 2.4 分割线 2.5 禁用的菜单项 3 按钮组 3.1 基本使用 ...

  9. Windows没有足够信息,不能验证该证书",是因为该证书的颁发者

    Windows没有足够信息,不能验证该证书",无法验证该证书的颁发者 解决方案之一: 1.win+R:打开运行 2.输入 gpedit.msc,确定,打开组策略 3.选择:计算机配置---管 ...

  10. FWT & FMT(位运算卷积)学习笔记

    它们两个的全名叫 快速沃尔什变换(FWT) 和 快速莫比乌斯变换(FMT),用来在 \(O(n\log n)\) 时间复杂度内求位运算卷积. 因为 FMT 能解决的问题是 FWT 的子集,所以这里不讲 ...