阻塞队列
java util concurrent 简述
JUC是JDK 1.5提供的一套专门用于并发编程的接口,帮助解决了并发环境下的一些问题
其他一些和并发相关的包有:
java.util.concurrent, java.util.concurrent.locks(锁相关), java.util.concurrent.atomic(原子性)
并发和并行
并发是值多个线程同时访问同一个资源
并行是指多个线程同时执行;所以并发是并行的一种。
JUC中包含的内容
BlockingQueue
ConcurrentMap
ExecutorService
Lock
Atomic
BlockingQueue
当我们需要用到队列,而且又是多线程环境,有希望能够有阻塞,可以考虑使用JUC的阻塞式队列
阻塞:程序执行时,如果无法得到预期结果,会hang住,不会往下执行,这个就叫做阻塞。
传统的Queue队列,队列已满时插入元素会报错;队列为空时获取元素会报错。
但是阻塞式队列,当队列已满时插入会等待;当队列为空时获取也会等待
阻塞队列具有的特点
1、遵循队列 FIFO(First In First Out) 的原则
2、具有 阻塞 的特点
3、队列都是定长的,这样才好控制阻塞,队列已满时。
4、不允许插入 null值
常见方法
add 非阻塞方法,如果队列已满,添加元素是抛异常: IllegalStateException
offer(element) 非阻塞方法,如果队列已满,返回false值
put 阻塞,永久阻塞
offer(element,5,TimeUtil.SECOND) 定时阻塞,超时后返回false
remove 非阻塞,队列为空时,获取元素抛出异常 :NoSuchElementException
poll 非阻塞方法,队列为空时,返回null值
take 获取元素,永久阻塞
poll(5,TimeUtil.SECOND) 定时阻塞
代码演示
ArrayBlockingQueue
"阻塞式顺序队列"
"1、底层是数组"
"2、创建时需要指定容量,指定容量后大小不可变"
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
// 需要指定容量,定长
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
// 添加元素
queue.add("a");
queue.add("a");
queue.add("a");
queue.add("a");
queue.add("a");
// 队列已满
// 抛出异常 - IllegalStateException
// queue.add("b");
// 返回false
// boolean flag = queue.offer("c");
// System.out.println(flag);
// 产生阻塞
// queue.put("d");
// 定时阻塞,返回false
boolean flag = queue.offer("e", 3, TimeUnit.SECONDS);
System.out.println(flag);
System.out.println(queue);
}
}
LinkedBlockingQueue
"底层是基于链式结构进行存储的——node"
"创建时可以指定容量,也可以不指定容量,如果指定了容量,那么容量不可变。"
"如果不指定容量,那么容量默认为Integer.MAX_VALUE,即21亿左右"
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class BlockingQueueDemo2 {
public static void main(String[] args) throws InterruptedException {
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>();
// 队列为空
// 抛出异常 - NoSuchElementException
// System.out.println(queue.remove());
// 返回null
// System.out.println(queue.poll());
// 产生阻塞
// System.out.println(queue.take());
// 定时阻塞
System.out.println(queue.poll(5, TimeUnit.SECONDS));
}
}
PriorityBlockingQueue
带优先级的阻塞队列。
"底层是一个数组""
"如果不指定容量的话,默认容量是11"
"底层使用的数据结构其实是一个二叉堆,所以该队列会默认排序"
"该队列对于插入其中的元素,会实现默认排序"
"所以要求,放入到该队列中的元素必须实现Comparable接口,定义其中的比较规则CompareTo方法实现自然排序"
"创建队列时,可以传入一个比较器Comparator对象,重写其中的compare(o1,o2)方法,重新指定比较规则"
"比较原则类似,比较结果大于0,当前元素(前一个元素)和后一个元素进行交换,反之小于0不交换"
import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue;
public class PriorityBlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
// PriorityBlockingQueue<String> queue = new PriorityBlockingQueue<>();
// queue.put("g");
// queue.put("a");
// queue.put("r");
// queue.put("u");
// queue.put("w");
// queue.put("l");
// queue.put("o");
/*
for(){
for(){
if(o1.compare(o2) > 0)
swap(o1, o2);
}
}
*/
// 按照分数进行降序排序
// Comparator<Student> c = new Comparator<Student>() {
// @Override
// public int compare(Student o1, Student o2) {
// return o2.getScore() - o1.getScore();
// }
// };
Comparator<Student> c = (s1, s2) -> s2.getScore() - s1.getScore();
PriorityBlockingQueue<Student> queue = new PriorityBlockingQueue<>(5, c);
queue.put(new Student("aaa", 50, 50));
queue.put(new Student("bbb", 28, 59));
queue.put(new Student("ccc", 35, 70));
queue.put(new Student("dd", 18, 62));
queue.put(new Student("eee", 40, 51));
for (int i = 0; i < 5; i++) {
System.out.println(queue.take());
}
}
}
class Student implements Comparable<Student> {
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
// 指定比较规则
// 如果this.compareTo(o)>0,那么this就排到o的后边
// 如果this.compareTo(o)<0,那么this就排到o的前边
// 在底层进行升序排序
// 按照年纪升序排序
// 升序排序:this - o
// 降序排序:o - this
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
SynchronousQueue
同步阻塞队列,队列的长度不需要给定,底层默认是1而且只能是1
BlockingDeque
阻塞式双端队列,允许两头进两头出,是一个接口
因为两头可以操作,所以常用的操作方法有12个。
例如:
addFirst,addLast
offerFirst,offerLast
putFirst,putLast