前段时间被人问到生成者跟消费者用java怎么实现,完全想不起来,后来回来看书的时候,正好看到这一段,就写了个demo,用来加深印象,记录一下。
我们这里主要使用了LinkBlockingQueue用来做队列,支撑起整个demo中两个线程直接的数据传递,LinkBlockingQueue最大的特点是可以设置的长度,使用put方法存取时,如果队列满了,会阻塞住,同样使用take读取删除项时,如果队列为空的时候,也会阻塞住,且put和take方法是并行的,互不干扰,非常适合做消息传递。
关于LinkBlockingQueue的原理,推荐大家看下面的链接,我这里只是记录demo,且也是才接触,对原理就不多做深入探讨了。链接如下:深入剖析java并发之阻塞队列LinkedBlockingQueue与ArrayBlockingQueue
1、首先我们来实现生产者 ProductThread,每两秒生产一条数据
import java.util.concurrent.BlockingQueue;
/**
* 生产者线程
*/
public class ProductThread extends Thread {
private BlockingQueue<String> queue;
public ProductThread(BlockingQueue<String> queue){
this.queue = queue;
}
@Override
public void run() {
int i=1;
while (true){
try {
queue.put("第: "+i+" 个"); //当队列满的时候,这个方法会阻塞住,等待队列有新的位置
System.out.println("放了第"+i+" 个--");
Thread.sleep(2000);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2、ConsumerThread,消费者线程,每3秒读取一次队列
import javax.sound.midi.Soundbank;
import java.util.concurrent.BlockingQueue;
/**
* 消费者队列
*/
public class ConsumerThread extends Thread {
private BlockingQueue<String> queue;
public ConsumerThread(BlockingQueue<String> queue){
this.queue = queue;
}
@Override
public void run() {
while (true){
try {
System.out.println("取出:"+queue.take()); //queue为空时,take方法会阻塞
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3、测试类ProducterAndConsumer,分别启动两个线程
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class ProducterAndConsumer {
public static void main(String[] args) {
BlockingQueue<String> queue = new LinkedBlockingQueue<>(100); //队列长度为100
new ProductThread(queue).start();
new ConsumerThread(queue).start();
}
}