java之应用阻塞队列实现生产者,消费者模式
java之使用阻塞队列实现生产者,消费者模式
在看代码之前,笔者先说几句题外话,生产者-消费者模式,一直是多线程编程中的经典设计模式,不仅仅提现在Java中,各个类C语言,以及其他的一些高级语言中都有实现,在Java 5之前,还没有出现阻塞队列的容器时,实现一个生产者消费者模式,相对来说比较复杂,代码量也比较大,最重要的是设计同步存取时更需要小心谨慎,一不小心就会带来莫名其妙的问题。
Java 5之前实现同步存取时,可以使用普通的一个集合,然后在使用线程的协作和线程同步可以实现生产者,消费者模式,主要的技术就是用好,wait ,notify,notifyAll,sychronized这些关键字。而在java 5之后,可以使用组阻塞队列来实现,此方式大大简少了代码量,使得多线程编程更加容易,安全方面也有保障。
BlockingQueue接口是Queue的子接口,它的主要用途并不是作为容器,而是作为线程同步的的工具,因此他具有一个很明显的特性,当生产者线程试图向BlockingQueue放入元素时,如果队列已满,则线程被阻塞,当消费者线程试图从中取出一个元素时,如果队列为空,则该线程会被阻塞,正是因为它所具有这个特性,所以在程序中多个线程交替向BlockingQueue中放入元素,取出元素,它可以很好的控制线程之间的通信。
下面给出代码实现
总之,利用好队列就可以用很少的代码量实现一个稳定,高效生产者,消费者模式,
。
在看代码之前,笔者先说几句题外话,生产者-消费者模式,一直是多线程编程中的经典设计模式,不仅仅提现在Java中,各个类C语言,以及其他的一些高级语言中都有实现,在Java 5之前,还没有出现阻塞队列的容器时,实现一个生产者消费者模式,相对来说比较复杂,代码量也比较大,最重要的是设计同步存取时更需要小心谨慎,一不小心就会带来莫名其妙的问题。
Java 5之前实现同步存取时,可以使用普通的一个集合,然后在使用线程的协作和线程同步可以实现生产者,消费者模式,主要的技术就是用好,wait ,notify,notifyAll,sychronized这些关键字。而在java 5之后,可以使用组阻塞队列来实现,此方式大大简少了代码量,使得多线程编程更加容易,安全方面也有保障。
BlockingQueue接口是Queue的子接口,它的主要用途并不是作为容器,而是作为线程同步的的工具,因此他具有一个很明显的特性,当生产者线程试图向BlockingQueue放入元素时,如果队列已满,则线程被阻塞,当消费者线程试图从中取出一个元素时,如果队列为空,则该线程会被阻塞,正是因为它所具有这个特性,所以在程序中多个线程交替向BlockingQueue中放入元素,取出元素,它可以很好的控制线程之间的通信。
下面给出代码实现
package com.queue; import java.util.concurrent.BlockingQueue; /*** * 消费者 * **/ public class Consumer extends Thread { /*** * 利用队列存储样品 * */ private BlockingQueue<String> bq; public Consumer() { // TODO Auto-generated constructor stub } public Consumer(BlockingQueue<String> bq) { super(); this.bq = bq; } @Override public void run() { while(true){ System.out.println(getName()+"消费者准备消费集合元素"); try{ Thread.sleep(2000); //尝试取出元素,如果队列为空,则被线程阻塞 bq.take(); }catch(Exception e){ e.printStackTrace(); } System.out.println(getName()+"消费完成"+bq); } } }
package com.queue; import java.util.concurrent.BlockingQueue; /** * 生产者 * **/ public class Producer extends Thread{ /*** * 利用队列存储样品 * */ private BlockingQueue<String> bq; public Producer() { // TODO Auto-generated constructor stub } public Producer(BlockingQueue<String> bq) { this.bq = bq; } @Override public void run() { String []str=new String[]{"solr","lucene","nutch"}; for(int i=0;i<99999999;i++){ System.out.println(getName()+"生产者准备生产集合元素了!"); try{ Thread.sleep(2000); //尝试放入元素,如果对列已满,则线程被阻塞 bq.put(str[i%3]); }catch(Exception e){ e.printStackTrace(); } System.out.println(getName()+"生产完成:"+bq); } } }
package com.queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; /** * 生产者,消费者测试 * * **/ public class BlockingQueueTest { public static void main(String[] args) { //创建一个容量为1的队列 BlockingQueue<String> bq=new ArrayBlockingQueue<>(1); //启动三个生产者线程 new Producer(bq).start(); new Producer(bq).start(); new Producer(bq).start(); //启动一个消费者线程 new Consumer(bq).start(); } }
Thread-0生产者准备生产集合元素了! Thread-1生产者准备生产集合元素了! Thread-2生产者准备生产集合元素了! Thread-3消费者准备消费集合元素 Thread-0生产完成:[solr] Thread-0生产者准备生产集合元素了! Thread-3消费完成[] Thread-3消费者准备消费集合元素 Thread-1生产完成:[solr] Thread-1生产者准备生产集合元素了! Thread-3消费完成[solr] Thread-2生产完成:[solr] Thread-2生产者准备生产集合元素了! Thread-3消费者准备消费集合元素 Thread-3消费完成[lucene] Thread-3消费者准备消费集合元素 Thread-0生产完成:[lucene] Thread-0生产者准备生产集合元素了!
总之,利用好队列就可以用很少的代码量实现一个稳定,高效生产者,消费者模式,