java 多线程系列文章列表, 请查看目录: 《java 多线程学习笔记》
1. 线程通信-阻塞队列
1.1 阻塞API
BlockingQueue 接口提供了两个阻塞方法:
- void put(E e) throws InterruptedException: 像队列中添加元素, 如果队列已满, 则阻塞该线程.
- E take() throws InterruptedException: 从队列中取出元素, 如果队列为空, 则阻塞该线程.
1.2 常见的阻塞队列
BlockingQueue 有以下几个实现类:
- ArrayBlockingQueue: 基于数组实现的阻塞队列
- LinkedBlockingQueue: 基于连表实现的阻塞队列
- SynchronousQuue: 同步队列, 该队列的存取必须交替进行. 也就是说队列中最多只能有一个元素.
- PriorityBlockingQuue: 并非标准的阻塞队列, 不是按先进先出方式存取, 而是按优先级排序存取.
- DelayQueue: 特殊的阻塞队列, 要求所有元素必须都实现Delay 接口.
2. 阻塞队列示例
2.1 使用阻塞队列改造Product
使用阻塞队列改造Product时, 无须再使用synchronized 或Lock 添加锁
public class Product {
// 阻塞队列, 设置容量为1. 当容量为1时, 可替换为SynchronousQueue
private BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);
public void sale(){
try {
String poll = queue.take();
System.out.println(Thread.currentThread().getName() + "-获取商品:" + poll);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void purchase() {
try {
String product = "product-" + new Random().nextInt(10);
queue.put(product);
System.out.println(Thread.currentThread().getName() + "-生产商品:" + product);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.2 测试
public static void main(String[] args) {
Product product = new Product();
// 启动三个线程消费
for (int i = 0; i < 3; i++) {
new Thread("消费者" + i){
@Override
public void run() {
while (true) {
product.sale();
}
}
}.start();
}
// 启动一个线程生产
new Thread("生产者"){
@Override
public void run() {
while (true) {
product.purchase();
ThreadUtil.sleep(10);
}
}
}.start();
ThreadUtil.sleep(10000);
}
2.3 输出
消费者0-获取商品:product-4
生产者-生产商品:product-4
生产者-生产商品:product-8
消费者1-获取商品:product-8
生产者-生产商品:product-9
消费者2-获取商品:product-9
生产者-生产商品:product-6
消费者0-获取商品:product-6
生产者-生产商品:product-2