zoukankan      html  css  js  c++  java
  • Java中的阻塞队列

    1.什么是阻塞?

    答:不满足条件的线程会处于等待状态就叫阻塞。标准的就是生产者消费者存储模型。不满足条件的生产者/消费者要阻塞。

    2.什么是队列?

    答:队列是先进先出的数据结构,

    3.什么是阻塞队列?

    答:阻塞队列(BlockingQueue)支持两个操作,添加和取出:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。

    4.阻塞队列本身源码,就已经给你实现了锁的机制,保证多线程的正确读取顺序。减少了我们自己写生产者消费者存储模型时要用的锁。

    4. Java里的阻塞队列

    JDK7提供了7个阻塞队列。分别是:

    • ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
    • LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
    • PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
    • DelayQueue:一个使用优先级队列实现的无界阻塞队列。
    • SynchronousQueue:一个不存储元素的阻塞队列。
    • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
    • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

    4.使用BlockingQueue的关键技术点如下: 
        1.BlockingQueue定义的常用方法如下: 
            1)add(anObject):把anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则报异常 
            2)offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false. 
            3)put(anObject):把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续. 
            4)poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null 
            5)take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止 

    5. BlockingQueue有四个具体的实现类,根据不同需求,选择不同的实现类 
            1)ArrayBlockingQueue:规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小.其所含的对象是以FIFO(先入先出)顺序排序的. 
            2)LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定.其所含的对象是以FIFO(先入先出)顺序排序的 
            3)PriorityBlockingQueue:类似于LinkedBlockQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数的Comparator决定的顺序. 
            4)SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的. 

    6.队列也是一种容器,用来存储对象的。所以其中的对象要有相应的存储顺序。

    1 package com.thread;
     2 import java.util.concurrent.ArrayBlockingQueue;
     3 import java.util.concurrent.BlockingQueue;
     4 
     5 public class BlockingQueueTest {
     6     public static void main(String[] args) {
     7         final BlockingQueue queue = new ArrayBlockingQueue(3);
     8         for(int i=0;i<2;i++){
     9             new Thread(){
    10                 public void run(){
    11                     while(true){
    12                         try {
    13                             Thread.sleep((long)(Math.random()*1000));
    14                             System.out.println(Thread.currentThread().getName() + "准备放数据!");                            
    15                             queue.put(1);
    16                             System.out.println(Thread.currentThread().getName() + "已经放了数据," +                             
    17                                         "队列目前有" + queue.size() + "个数据");
    18                         } catch (InterruptedException e) {
    19                             e.printStackTrace();
    20                         }
    21 
    22                     }
    23                 }
    24                 
    25             }.start();
    26         }
    27         
    28         new Thread(){
    29             public void run(){
    30                 while(true){
    31                     try {
    32                         //将此处的睡眠时间分别改为100和1000,观察运行结果
    33                         Thread.sleep(1000);
    34                         System.out.println(Thread.currentThread().getName() + "准备取数据!");
    35                         queue.take();
    36                         System.out.println(Thread.currentThread().getName() + "已经取走数据," +                             
    37                                 "队列目前有" + queue.size() + "个数据");                    
    38                     } catch (InterruptedException e) {
    39                         e.printStackTrace();
    40                     }
    41                 }
    42             }
    43             
    44         }.start();            
    45     }
    46 }

    7. LinkedBlockingQueue和ArrayBlockingQueue比较起来,它们背后所用的数据结构不一样,导致LinkedBlockingQueue的数据吞吐量要大于ArrayBlockingQueue,但在线程数量很大时其性能的可预见性低于ArrayBlockingQueue.      

    • ArrayBlockingQueue是一个用数组实现的有界阻塞队列。此队列按照先进先出(FIFO)的原则对元素进行排序。默认情况下不保证访问者公平的访问队列,所谓公平访问队列是指阻塞的所有生产者线程或消费者线程,当队列可用时,可以按照阻塞的先后顺序访问队列,即先阻塞的生产者线程,可以先往队列里插入元素,先阻塞的消费者线程,可以先从队列里获取元素。通常情况下为了保证公平性会降低吞吐量。我们可以使用以下代码创建一个公平的阻塞队列:

      ArrayBlockingQueue fairQueue = new  ArrayBlockingQueue(1000,true);
      

      访问者的公平性是使用可重入锁实现的,代码如下:

       
      public ArrayBlockingQueue(int capacity, boolean fair) {
              if (capacity <= 0)
                  throw new IllegalArgumentException();
              this.items = new Object[capacity];
              lock = new ReentrantLock(fair);
              notEmpty = lock.newCondition();
              notFull =  lock.newCondition();
      }
      

      LinkedBlockingQueue是一个用链表实现的有界阻塞队列。此队列的默认和最大长度为Integer.MAX_VALUE。此队列按照先进先出的原则对元素进行排序。

      PriorityBlockingQueue是一个支持优先级的无界队列。默认情况下元素采取自然顺序排列,也可以通过比较器comparator来指定元素的排序规则。元素按照升序排列。

  • 相关阅读:
    SGU 271 Book Pile (双端队列)
    POJ 3110 Jenny's First Exam (贪心)
    HDU 4310 Hero (贪心)
    ZOJ 2132 The Most Frequent Number (贪心)
    POJ 3388 Japanese Puzzle (二分)
    UVaLive 4628 Jack's socks (贪心)
    POJ 2433 Landscaping (贪心)
    CodeForces 946D Timetable (DP)
    Android Studio教程从入门到精通
    Android Tips – 填坑手册
  • 原文地址:https://www.cnblogs.com/panxuejun/p/5956720.html
Copyright © 2011-2022 走看看