1、定义
- 生产者和消费者模式:假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费
- 如果仓库中没有产品,则生产者将产品放入仓库,如果仓库中有产品,则停止产生并等待,直到仓库中的产品消费者取走为止
- 如果仓库中放有产品,则消费则将产品拿出仓库,如果仓库中没有产品,则停止消费并等待,直到仓库中再次放入产品为止
2、wait/nofiy实现方式```
LinkedBlockingQueue或者ArrayBlockingQueue
package com.example.cp;
import java.util.ArrayList;
import java.util.List;
public class ThreadTest01 {
public static void main(String[] args) {
ArrayList<Bread> list = new ArrayList<Bread>();
Thread thread1 = new Thread(new Producer(list));
Thread thread2 = new Thread(new Consumer(list));
thread1.start();
thread2.start();
}
static class Bread{
private String s;
public Bread(String s){
this.s = s;
}
}
static class Producer implements Runnable{
private ArrayList<Bread> list;
public Producer(ArrayList<Bread> list){
this.list = list;
}
@Override
public void run() {
while(true){
synchronized (list){
if(list.size()>10){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Bread bread = new Bread("kent");
list.add(bread);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"生产了:"+bread.s);
System.out.println("生产中还剩下:"+list.size());
list.notify();
}
}
}
}
static class Consumer implements Runnable{
private ArrayList<Bread> list;
public Consumer(ArrayList<Bread> list){
this.list = list;
}
@Override
public void run() {
while(true){
synchronized (list){
if(list.size()==0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Bread remove = list.remove(0);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"消费了:"+remove.s);
System.out.println("消费中还剩下:"+list.size());
list.notify();
}
}
}
}
}
3、阻塞队列 BlockingQueue
package com.example.cp;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class ThreadTest03 {
private static BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);
public static void main(String[] args) {
Thread producerThread = new Thread(() -> {
int i = 0;
while(true) {
try {
queue.put(++i);
Thread.sleep(500);
System.out.println("Produced: " + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread consumerThread1 = new Thread(() -> {
while(true) {
try {
Thread.sleep(500);
int value = queue.take();
System.out.println("Consumed1: " + value);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread consumerThread2 = new Thread(() -> {
while(true) {
try {
int value = queue.take();
Thread.sleep(1000);
System.out.println("Consumed2: " + value);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producerThread.start();
consumerThread1.start();
consumerThread2.start();
}
}
```
LinkedBlockingQueue和ArrayBlockingQueue的区别
LinkedBlockingQueue和ArrayBlockingQueue都是Java中常用的阻塞队列,它们有以下几点不同:
- 实现方式:LinkedBlockingQueue是一个由链表实现的有界队列,而ArrayBlockingQueue是一个对象数组+一把锁+两个条件实现的阻塞队列。
- 容量限制:LinkedBlockingQueue的容量限制是可选的,如果在初始化时没有指定容量,那么默认使用int的最大值作为队列容量。而ArrayBlockingQueue必须指定大小,即容量有限。
- 线程安全性:LinkedBlockingQueue的内部实现添加和删除是使用两个ReentrantLock来控制并发,而ArrayBlockingQueue只使用了一个。
- 吞吐量:在正常情况下,LinkedBlockingQueue的吞吐效率比ArrayBlockingQueue的效率要高。
- 内存模型:LinkedBlockingQueue的内存模型比ArrayBlockingQueue更加灵活,可以更好地支持并发操作。
- 性能:在CPU缓存友好性方面,LinkedBlockingQueue比ArrayBlockingQueue更好,因为链表的节点比数组的元素更容易被CPU缓存。
- 适用场景:LinkedBlockingQueue适用于处理大量数据或高并发场景,而ArrayBlockingQueue适用于处理少量数据或低并发场景。
总的来说,LinkedBlockingQueue相对于ArrayBlockingQueue更加灵活、高效和适用于高并发场景,而ArrayBlockingQueue则相对简单和适用于低并发场景。