阻塞队列BlockingQueue

BlockingQueue作为线程同步的工具,并不是作为一个容器使用,它具有一个特征:当生产者线程试图向其放入元素的时候,如果队列已满,则该线程被阻塞,当消费者线程试图从BlockingQueue中取出元素时,如果队列已空,则该线程阻塞。

BlockingQueue在jdk文档里面有如下几个方法:

  抛出异常 特殊值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用

 

BlockingQueue的实现子类有如下几个:

ArrayBlockingQueue:基于数组实现的阻塞队列,在创建ArrayBlockingQueue对象时必须制定容量大小。并且可以指定公平性与非公平性,默认情况下为非公平的,即不保证等待时间最长的队列最优先能够访问队列。

LinkedBlockingQueue:基于链表实现的阻塞队列,在创建LinkedBlockingQueue对象时如果不指定容量大小,则默认大小为Integer.MAX_VALUE。

PriorityBlockingQueue:以上2种队列都是先进先出队列,而PriorityBlockingQueue却不是,它会按照元素的优先级对元素进行排序,按照优先级顺序出队,每次出队的元素都是优先级最高的元素。注意,此阻塞队列为无界阻塞队列,即容量没有上限。
 

用Condition来模拟一个阻塞队列,假定有一个绑定的缓冲区,它支持 puttake 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition实例来做到这一点

 

class BoundedBuffer {
  final Lock lock = new ReentrantLock();
  final Condition notFull = lock.newCondition();
  final Condition notEmpty = lock.newCondition();

 final Object[] items = new Object[100];
 int putptr, takeptr, count;

 public void put(Object x) throws InterruptedException {
  lock.lock();
  try {
   while (count == items.length)
    notFull.await();
   items[putptr] = x;
   if (++putptr == items.length)
    putptr = 0;
   ++count;
   notEmpty.signal();
  } finally {
   lock.unlock();
  }
 }

 public Object take() throws InterruptedException {
  lock.lock();
  try {
   while (count == 0)
    notEmpty.await();
   Object x = items[takeptr];
   if (++takeptr == items.length)
    takeptr = 0;
   --count;
   notFull.signal();
   return x;
  } finally {
   lock.unlock();
  }
 }
}

 

在多线程另一篇文章里面有一个题目(http://blog.csdn.net/erica_1230/article/details/38015291),启动三个线程循环十次交替打印出ABCABC,也可以用BlockingQueue来解决,代码如下:

package com.itcast.thread.blockingqueue;

import java.util.concurrent.*;
 

public class BlockingQueueOutput  {

 
private BlockingQueue<Integer>bqA=new ArrayBlockingQueue<Integer>(1);
private BlockingQueue<Integer>bqB=new ArrayBlockingQueue<Integer>(1);
private BlockingQueue<Integer>bqC=new ArrayBlockingQueue<Integer>(1);

{
 try {
  bqB.put(1);
  bqC.put(1);
 } catch (InterruptedException e) {
 
  e.printStackTrace();
 }
 
}

public void printA(){
 
 try {
  bqA.put(1);
  System.out.print("A");
  bqB.take();
  
 } catch (InterruptedException e) {
    e.printStackTrace();
 }
 
 
 
}

 

public void printB(){
 
 try {
  bqB.put(1);
  System.out.print("B");
  bqC.take();
  
 } catch (InterruptedException e) {
    e.printStackTrace();
 }
 
 
 
}

 

public void printC(){
 
 try {
  bqC.put(1);
  System.out.print("C");
  bqA.take();
  
 } catch (InterruptedException e) {
    e.printStackTrace();
 }
 
 
 
}


 
 
}

 

 


public class TestBlockingQueueThread {

 public static void main(String[] args) {
  BlockingQueueOutput out=new BlockingQueueOutput();
  A a=new A(out);
  B b=new B(out);
     C c=new C(out);
     a.start();
     b.start();
     c.start();

 }

}

 

跟以前的比是不是简洁了很多。

 

BlockingQueue也可以解决生产者和消费者问题:

 

 package com.itcast.heima2;
 
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
 
 public class BlockingQueueTest {
  
  class Producer extends Thread{
    
 
  private BlockingQueue<Integer>queue;
  
  public Producer(BlockingQueue<Integer>queue){
   this.queue=queue;
      }
  
  
  @Override
  public void run() {
   
   while(true){
      try {
    System.out.println(Thread.currentThread().getName()+"  准备生产 ");
       Thread.sleep(200);
    queue.put(1);
   } catch (InterruptedException e) {
    
    e.printStackTrace();
   }
      System.out.println(Thread.currentThread().getName()+"  生产完成: "+queue );
   }
   
   
  }
  
  
  }
  
  
  class Consumer extends Thread{
     
 
  private BlockingQueue<Integer>queue;
  
  public Consumer(BlockingQueue<Integer>queue){
   this.queue=queue;
      }
  
  
  @Override
  public void run() {
   
   while(true){
      try {
    System.out.println(Thread.currentThread().getName()+"  准备消费 ");
      Thread.sleep(200);
         queue.take();
   } catch (InterruptedException e) {
    
    e.printStackTrace();
   }
      System.out.println(Thread.currentThread().getName()+"  消费完成: "+queue );
   }
   
   
  }
  
  
  }
  
  
 
  public static void main(String[] args) {
   BlockingQueue<Integer>bq=new ArrayBlockingQueue<Integer>(1);
   BlockingQueueTest test=new BlockingQueueTest();
   //启动是3个生产者
   test.new Producer(bq).start();
   test.new Producer(bq).start();
   test.new Producer(bq).start();
   //启动一个消费者
   test.new Consumer(bq).start();
   
 
  }
 
 }

打印结果:

Thread-0  准备生产
Thread-1  准备生产
Thread-2  准备生产
Thread-3  准备消费
Thread-2  生产完成: [1]
Thread-2  准备生产
Thread-3  消费完成: [1]
Thread-3  准备消费
Thread-0  生产完成: [1]
Thread-0  准备生产
Thread-3  消费完成: []
Thread-3  准备消费
Thread-1  生产完成: [1]

.......................................

只要一个线程向其中生产一个元素以后,其他的生产者线程都要等待,直到有消费者线程去消费为止。

 

 

 

 

你可能感兴趣的:(java,多线程)