多线程中的BlockingQueue(阻塞队列)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LiuXudongHnu/article/details/61924861

       JAVA5中提供了一个BlockingQueue接口,虽然它是Queue的子接口,但它的主要作用并不是容器,而是作为线程同步的工具。多线程的环境中,通过队列可以实现数据共享,比如生产者消费者模型中,通过队列可以实现数据共享。但是如果生产者的生产速度和消费者的消费速度不匹配的话,很容易造成队列满了,生产者无法把数据放进去或者队列没有数据,消费者无法从中获得数据。BlockingQueue的特征便是:当生产者试图向BlockingQueue中放入元素时,如队列满了,那么这个生产者的线程阻塞,当消费者试图从BlockingQueue中取出元素时,如果队列空了,那么消费者线程阻塞。

       BlockingQueue中的方法:队尾插入元素时,有add(e),offer(e),put(e),offer(e,time,unit)四种方法。区别在于当队列满时,4中方法分别抛出异常,返回false、阻塞队列、等待一定时间若还未成功则返回false。队头删除元素并返回删除的元素时,有remove(),poll(),take(),poll(time,unit)四种方法,区别在于队列没元素时分别跑出异常、返回false、阻塞队列、等待一定时间仍为成功则返回false。获取、不删除元素两种方法element(),peek()。当队列空时,这两种方法分别返回异常和返回false。

       BlockingQueue的一些实现类:1、ArrayBlockingQueue:基于数组实现的BlockingQueue。其内部维护了一个定长的数组用于缓存队列中的数据对象。其内部还保存着两个整形变量,分别标示队列的头部和尾部在队列中的位置。2、LinkedBlockingQueue:基于链表实现的BlockingQueue队列。内部维持着一个数据缓冲队列,该队列由一个链表构成。需要注意的是,如果在构造一个LinkerBlockingQueue时,没有指定其大小,它会默认一个无限容量的大小,如果生产者远大于消费者,那么系统内存会耗尽。3、PriorityBlockingQueue:该队列在调用remove(),poll(),take()方法时,并不是取出在队列中存在时间最长的元素,而是取出队列中最小的元素。其判断元素的大小会根据元素的本身大小来自然排序,也可以使用Comparator来定制排序。4、DelayQueue:底层用PriorityBlockingQueue实现,只有当指定延迟的时间到了,才能从中拿走元素,并且因为其没有大小限制,所以插入时不会阻塞,获取时才有可能阻塞。5、SynchronousQueue:同步队列,对该队列的存取操作必须交替进行。

class Producer extends Thread{
	
	private BlockingQueue<String>  bq;
	
	public Producer(BlockingQueue<String> bq){
		this.bq=bq;
	}
	
	public void run(){
		String[] strArr=new String[]{
				"JAVA","C++","Spring"
		};
		for(int i=0;i<9999999;i++){
			System.out.println(getName()+"生产者准备生产集合元素~!");
			try {
				Thread.sleep(200);
			    bq.put(strArr[i%3]); //尝试放入元素,如果队列满,则线程阻塞。
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
			System.out.println(getName()+"生产完成:"+bq);
		}
	}	
}

class Consumer extends Thread{
	private BlockingQueue<String> bq;
	
	public Consumer(BlockingQueue<String> bq){
		this.bq=bq;
	}
	
	public void run(){
		while(true){
			System.out.println(getName()+"消费者准备消费集合元素!");
			try{
				Thread.sleep(200);
				bq.take();    //尝试取出元素,如果空,则阻塞。
			}catch(Exception e){
				e.printStackTrace();
			}
			System.out.println(getName()+"消费完成"+bq);
		}
	}
	
}

public class BlockingQueueTest2 {

	public static void main(String[] args){
		BlockingQueue<String> bQueue=new ArrayBlockingQueue<String>(1); //创建以个容量为1的BlockingQueue~!
		//启动三个生产者
		new Producer(bQueue).start();
		new Producer(bQueue).start();
		new Producer(bQueue).start();
		//启动一个消费者
		new Consumer(bQueue).start();
	}
	
}

上述程序中,由于BlockingQueue集合的容量只有1,因此三个生产者线程无法连续放入元素,必须等消费者取出元素,三个生产者线程其中之一才能放入线程,其中一个放入后,其他的必须等待。

猜你喜欢

转载自blog.csdn.net/LiuXudongHnu/article/details/61924861
今日推荐