1.JUC简介
JUC(java.util.concurrent)是JDK1.5提供一套用于应对高并发的包:
- java.util.concurrent
- java.util.concurrent.atomic
- java.util.concurrent.lock
JUC包含5部分内容:
- BlockingQueue
- ConcurrentMap
- ExecutorService
- Lock
- Atomic
2.BlockingQueue
2.1 概述:
- 特征:阻塞,FIFO
- 阻塞式队列往往是有界的 - 队列的容量往往是固定的
- 阻塞:当队列为空的时候,试图获取元素的线程会被阻塞;当队列已满的时候,试图放入元素的线程会被阻塞
- 重要方法
| 抛出异常 | 返回值 | 永久阻塞 | 定时阻塞 |
添加 | add - IllegalStateException | offer - false | put | offer |
移除 | remove - NoSuchElementException | poll - null | take | poll |
- 阻塞式队列中不允许元素为null
- 适合于生产消费模型
队列为空返回null,返回null队列为空
2.2实现类
1.ArrayBlockingQueue - 阻塞式顺序队列
- 底层依靠数组来存储数据
- 使用的时候需要指定容量,并且容量不可变
2.LinkedBlockingQueue - 阻塞式链式队列
- LinkedBlockingQueue的使用方法和ArrayBlockingQueue是一样的,只有底层实现是不一样
- LinkedBlockingQueue底层是基于节点来实现的 - 单向链表
- 在使用的时候可以指定容量,容量指定之后是不可变的。也可以不指定容量,如果不指定则容量默认为Integer.MAX_VALUE,即231-1。因为实际生产过程中,不会向一个队列中添加21亿个值,所以一般认为此时队列的容量是无限的
3.PriorityBlockingQueue - 具有优先级的阻塞式队列
- 底层基于数组来进行存储,但是本质上是将这个数组扭转成了一个二叉树来进行存储
- 如果不指定容量,则默认初始容量是11,用满之后会扩容
- 会对放入队列中的元素自动的进行排序,要求元素对应的类必须实现Comparable接口,覆盖compareTo方法
- 如果需要在构建队列的时候额外指定比较规则,那么可以传入一个Comparator对象
- 在迭代过程中不保证排序
4.SynchronousQueue - 同步队列 - 在使用的时候不需要指定容量,这个队列的容量默认为1且只能为1
扩展:BlockingDeque - 阻塞式双向/双端队列 - 允许从两端放入元素或者获取元素
2.3代码示例
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
// 创建队列
BlockingQueue<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 b = queue.offer("b");
// System.out.println(b);
// 产生阻塞
// queue.put("b");
// 定时阻塞
boolean b = queue.offer("b", 5, TimeUnit.SECONDS);
System.out.println(b);
System.out.println(queue);
}
}
public class BlockingQueueDemo2 {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<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));
}
}
当在queue中put 字母时,会按照字母顺序排序,如果添加的是对象,可以编写比较器,如以下示例,可以用分数进行升序或者降序排序
package blockingqueue;
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("r");
// queue.put("a");
// queue.put("t");
// queue.put("h");
// queue.put("e");
// queue.put("o");
// queue.put("m");
// 队列中的元素能够按照分数进行降序排序
Comparator<Student> c = (o1, o2) -> o2.getScore() - o1.getScore();
PriorityBlockingQueue<Student> queue =
new PriorityBlockingQueue<>(4, c);
queue.put(new Student("张三", 50, 59));
queue.put(new Student("李四", 28, 70));
queue.put(new Student("王五", 38, 75));
queue.put(new Student("赵六", 19, 62));
// for (int i = 0; i < 4; i++) {
// System.out.println(queue.take());
// }
for (Student s : queue) {
System.out.println(s);
}
}
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
// 要求:按照年龄升序
// 指定比较规则
// 升序:this-o
// 降序:o-this
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}