生产者和消费者
前言
生产者-消费者模型是一个常见的多线程编程模型
图片来自网络
一个队列中,多个生产者线程往队列中放数据,对个消费者线程从队列中获取数据。
要实现这么一个编程模型,需要怎么做?
实现
- 1 首先,我们的队列需要加锁,确保读写数据安全
- 2 阻塞,当我们的队列满了,此时需要消费,阻塞生产,通知消费;队列为空,阻塞消费,通知生产。
- 3 双向通知,如2
思考
- 1 如何阻塞 ?
重试? 睡眠几秒重试?自旋?
等待? - 2 如何通知?
wait() 和 notify()或者 lock接口的condition机制
关于生产者消费设计模式
一个负责生产 一个负责消费
可以启动多个进行生产,也可以启动多个消费,最主要的是做好边界控制以及数据同步,写读互斥。
简单的有锁实现,有锁当然会影响性能,当然写不是很频繁的话,也可以使用这种去实现
这里使用thread 原生方法去实现生产者以及消费者,当然也可以使用Lock锁的condition信号和通知去实现
具体实现代码
package thread.thread;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
/**
* 生产者和消费者
*/
public class ProductAndConsumerTest {
private static final int LINED_SIZE = 1000;
private static int num = 0;
private static Object lock = new Object();
private static final LinkedList<Integer> linkedList = new LinkedList<>();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new ConsumerObje(), " 消费者1");
Thread t2=new Thread(new ProductAndConsumerTest.ConsumerObje(), " 消费者2");
Thread t3 =new Thread(new ProductAndConsumerTest.ProductObje(), " 生产者1");
t1.start();
t2.start();
t3.start();
t1.setPriority(5);
t2.setPriority(5);
t3.setPriority(5);
t1.join();
t2.join();
t3.join();
TimeUnit.SECONDS.sleep(2);
System.out.println(" main end ");
}
static class ConsumerObje implements Runnable {
@Override
public void run() {
while (true){
synchronized (lock) {
while (linkedList.size() == 0) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(5_00);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " : " + linkedList.removeFirst());
lock.notifyAll();
}
}
}
}
static class ProductObje implements Runnable {
@Override
public void run() {
while (true) {
synchronized (lock) {
while (linkedList.size() >= LINED_SIZE) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int n = num++;
System.out.println(" 正在生产: " + n);
linkedList.addLast(n);
lock.notifyAll();
}
}
}
}
}
这里有个疑问?
synchronized (lock) {
while (linkedList.size() >= LINED_SIZE) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
此段代码 ,在wait等待的时候,进入阻塞状态,一直不能退出synchronized代码块,那么线程永远无法进入synch代码块里,永远没有机会Notify()了,死锁了?
其实这里不会死锁的。
在wait()内部,会先释放lock对象的锁,然后进入阻塞状态,之后会被另一个线程notify唤醒,再重新去获取锁。
wait()调用完成后,执行后面的业务逻辑代码,然后退出sync同步块,再次释放锁。
为什么wait() ,notify()和synchronized一起使用
wait(),notify()是Object的函数,而synchronized锁的是一个对象锁,不能是Thread所特有的。