1.概念
在并发编程中,经常会提到生产者和消费者模式这一概念,这个东西往往是用来提高并发编程的效率的。所谓生产者就是产生数据的线程,所谓消费者,就是消费数据的线程。再多线程并发编程中,很有可能出现生产者的身生产速度和消费者的消费速度不一致的时候,如果不采取一定的措施,肯定是会储出现意想不到的后果的,所以,往往会用一个阻塞队列来充当一个缓冲区的作用,生产者生产的数据全部放倒阻塞队列中,消费者校消费数据的时候也从阻塞队列中去那,这就可以平衡生产者和消费者的数据处理能力。
2.实现
解决生产者和消费者的关键在于使用一个阻塞队列充当缓冲区,而这个阻塞队列必须具备两个特点:1.在取数据的时候,如果队列为空,取数据的线程必须被阻塞,直到生产者生产的新的数据并且放入队列为止。2.在生产数据的时候,如果发现队列满了,此时生产者必须被阻塞,直到阻塞队列有了空位为止,才能继续生产。
在Java中,LinkedBlockingQueue
的take()
和put()
方法正好符合这两个条件,并且是线程安全的。
take()
:在队列为空的时候会阻塞,直到有队列有新的元素进来。
put()
: 在队列满了的时候会阻塞,直到队列有了新的空位。
还是直接上代码吧:
public class ProducerAndConsumer {
static BlockingQueue<Fruit> fruitsBuffer = new LinkedBlockingQueue<>();
public static void main(String[] args) {
Thread p1 = new Thread(new Producer(fruitsBuffer), "producer 1 ");
Thread c1 = new Thread(new Consumer(fruitsBuffer),"consumer 1 ");
Thread c2 = new Thread(new Consumer(fruitsBuffer),"consumer 2 ");
Thread c3 = new Thread(new Consumer(fruitsBuffer),"consumer 3 ");
p1.start();
c1.start();
c2.start();
c3.start();
}
//生产者
static class Producer implements Runnable {
BlockingQueue<Fruit> productsBuffer;
public Producer(BlockingQueue<Fruit> productsBuffer) {
this.productsBuffer = productsBuffer;
}
@Override
public void run() {
try {
for (int i = 0; i < 30; i++) {
System.out.println(Thread.currentThread().getName() + ":生产者开始生产商品了!");
productsBuffer.put(new Fruit( "水果:"+ i));
System.out.println(Thread.currentThread().getName() + ":这一次生产结束了");
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Consumer implements Runnable {
BlockingQueue<Fruit> productsBuffer;
public Consumer(BlockingQueue<Fruit> productsBuffer) {
this.productsBuffer = productsBuffer;
}
@Override
public void run() {
while (true) {
try {
Fruit product = productsBuffer.take();
System.out.println(Thread.currentThread().getName()+"本次消费的产品是:" + product);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//产品,水果
static class Fruit {
String name;
public Fruit(String name) {
this.name = name;
}
@Override
public String toString() {
return "Fruit{" +
"name='" + name + '\'' +
'}';
}
}
}
可以看到,1个生产者和3个消费者共享了一个阻塞队列,无论数据发送得快,还是慢,最中都会被正确地处理。