使用阻塞队列实现生产者与消费者
对于生产者与消费者是多线程中非常重要的一种实现,生产者生产的产品放入队列中,消费者消费队列中的产品,如果队列中没有了产品,消费者不再消费,如果队列中的产品满了,生产者就不再生产,对于生产者与消费者的实现,本文提供了两种方法:
- 利用java提供的阻塞队列实现消费者与生产者
- 自己写一个实现消费者与生产者的队列类
1.利用java提供的阻塞队列实现消费者与生产者
package com.hangzhou.victor.testsynchronized;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* @description: 阻塞队列实现生产者与消费者
* @author: victor
* @date: 2018/12/24 17:25
*/
public class TestArrayBlockingQueue {
public static void main(String[] args) {
BlockingQueue<Character> bq = new LinkedBlockingQueue<>(5);
new Thread(() -> {
for (char i = 'A'; i <= 'G'; i++) {
try {
System.out.println("生产者生产:" + i);
bq.put(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
for (int i = 0; i < 7; i++) {
try {
Character poll = bq.take();
System.out.println("消费者消费:" + poll);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
这里生产者与消费者只提供了一个线程,也可以提供多个线程,这里都是一样的,不再赘述。
对于阻塞队列,选择哪个都是一样的,只不过LinkedBlockingQueue有空参构造方法,ArrayBlockingQueue没有空参构造方法,创建时必须指定容量,但是,他们使用的方法都是
put()
和take()
。对于阻塞队列一定要用其中的
put()
和take()
方法才能实现生产者与消费者线程的阻塞,具体其他方法的描述请参考java API。
2. 自己写一个实现消费者与生产者的队列类
package com.hangzhou.victor.testsynchronized;
import java.util.ArrayList;
import java.util.List;
/**
* @Description: 生产者与消费者
* @author: victor
* @date: 2020/10/9 21:33
*/
public class TestProducerAndConsumer {
public static void main(String[] args) {
MyQueue mq = new MyQueue();
Producer1 p1 = new Producer1(mq);
Producer2 p2 = new Producer2(mq);
Consumer c1 = new Consumer(mq);
Consumer c2 = new Consumer(mq);
p1.start();
p2.start();
c1.start();
c2.start();
}
}
class Consumer extends Thread {
MyQueue mq;
public Consumer(MyQueue mq) {
this.mq = mq;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(mq.poll()+"被"+Thread.currentThread().getName()+"移除");
}
}
}
class Producer1 extends Thread {
MyQueue mq;
public Producer1(MyQueue mq) {
this.mq = mq;
}
@Override
public void run() {
for (char ch = 'A'; ch <= 'E'; ch++) {
mq.offer(ch);
}
}
}
class Producer2 extends Thread {
MyQueue mq;
public Producer2(MyQueue mq) {
this.mq = mq;
}
@Override
public void run() {
for (char ch = 'F'; ch <= 'J'; ch++) {
mq.offer(ch);
}
}
}
class MyQueue { //myqueue是临界资源
private List vaules = new ArrayList();
private int max = 4;
public synchronized void offer(Object obj) {
while (vaules.size() >= max) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
System.out.println(Thread.currentThread().getName() + "存入第" + (vaules.size() + 1) + "个值");
vaules.add(obj);
}
public synchronized Object poll() {
while (vaules.size() == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll(); //唤醒因mq对象而进入无限期等待的线程对象所有
return vaules.remove(0);
}
public void show() {
for (Object vaule : vaules) {
System.out.println(vaule);
}
}
}
这里自己的实现感觉还是比较麻烦的,推荐第一种写法。
当队列中的产品生产满了之后,生产者线程就进入阻塞状态,当队列中的产品消费完之后,消费者线程就进入阻塞状态,无论生产者和消费者都要唤醒所有的线程,以防止生产者只唤醒了生产者,消费者只唤醒了消费者导致无限阻塞状态。