`
y806839048
  • 浏览: 1119220 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

BlockingQueue深入分析

阅读更多
多线程的共享也可以用全局变量做,全局变量可以用queue也可以不出现线程问题,局部变量需要用blockqueue才可以解决
 
 
1.BlockingQueue定义的常用方法如下
  抛出异常 特殊值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e,time,unit)
移除 remove() poll() take() poll(time,unit)
检查 element() peek() 不可用 不可用
 

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有新的对象被加入为止

其中:BlockingQueue 不接受null 元素。试图addput 或offer 一个null 元素时,某些实现会抛出NullPointerExceptionnull 被用作指示poll 操作失败的警戒值。 
 

2、BlockingQueue的几个注意点

【1】BlockingQueue 可以是限定容量的。它在任意给定时间都可以有一个remainingCapacity,超出此容量,便无法无阻塞地put 附加元素。没有任何内部容量约束的BlockingQueue 总是报告Integer.MAX_VALUE 的剩余容量。

【2】BlockingQueue 实现主要用于生产者-使用者队列,但它另外还支持Collection 接口。因此,举例来说,使用remove(x) 从队列中移除任意一个元素是有可能的。然而,这种操作通常 会有效执行,只能有计划地偶尔使用,比如在取消排队信息时。

【3】BlockingQueue 实现是线程安全的。所有排队方法都可以使用内部锁或其他形式的并发控制来自动达到它们的目的。然而,大量的 Collection 操作(addAllcontainsAllretainAll 和removeAll没有 必要自动执行,除非在实现中特别说明。因此,举例来说,在只添加了c 中的一些元素后,addAll(c) 有可能失败(抛出一个异常)。

【4】BlockingQueue 实质上不支持使用任何一种“close”或“shutdown”操作来指示不再添加任何项。这种功能的需求和使用有依赖于实现的倾向。例如,一种常用的策略是:对于生产者,插入特殊的end-of-stream 或poison 对象,并根据使用者获取这些对象的时间来对它们进行解释。
 
3、简要概述BlockingQueue常用的四个实现类
 
 

1)ArrayBlockingQueue:规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小.其所含的对象是以FIFO(先入先出)顺序排序的.

2)LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定.其所含的对象是以FIFO(先入先出)顺序排序的

3)PriorityBlockingQueue:类似于LinkedBlockQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数的Comparator决定的顺序.

4)SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的.

    
其中LinkedBlockingQueueArrayBlockingQueue比较起来,它们背后所用的数据结构不一样,导致LinkedBlockingQueue的数据吞吐量要大于ArrayBlockingQueue,但在线程数量很大时其性能的可预见性低于ArrayBlockingQueue.  
 
下面主要看一下ArrayBlockingQueue的源码:
[java] view plain copy
 
  1. public boolean offer(E e) {      
  2.         if (e == nullthrow new NullPointerException();      
  3.         final ReentrantLock lock = this.lock;//每个对象对应一个显示的锁      
  4.         lock.lock();//请求锁直到获得锁(不可以被interrupte)      
  5.         try {      
  6.             if (count == items.length)//如果队列已经满了      
  7.                 return false;      
  8.             else {      
  9.                 insert(e);      
  10.                 return true;      
  11.             }      
  12.         } finally {      
  13.             lock.unlock();//      
  14.         }      
  15. }      
  16. 看insert方法:      
  17. private void insert(E x) {      
  18.         items[putIndex] = x;      
  19.         //增加全局index的值。      
  20.         /*    
  21.         Inc方法体内部:    
  22.         final int inc(int i) {    
  23.         return (++i == items.length)? 0 : i;    
  24.             }    
  25.         这里可以看出ArrayBlockingQueue采用从前到后向内部数组插入的方式插入新元素的。如果插完了,putIndex可能重新变为0(在已经执行了移除操作的前提下,否则在之前的判断中队列为满)    
  26.         */     
  27.         putIndex = inc(putIndex);       
  28.         ++count;      
  29.         notEmpty.signal();//wake up one waiting thread      
  30. }      
 
[java] view plain copy
 
  1. public void put(E e) throws InterruptedException {      
  2.         if (e == nullthrow new NullPointerException();      
  3.         final E[] items = this.items;      
  4.         final ReentrantLock lock = this.lock;      
  5.         lock.lockInterruptibly();//请求锁直到得到锁或者变为interrupted      
  6.         try {      
  7.             try {      
  8.                 while (count == items.length)//如果满了,当前线程进入noFull对应的等waiting状态      
  9.                     notFull.await();      
  10.             } catch (InterruptedException ie) {      
  11.                 notFull.signal(); // propagate to non-interrupted thread      
  12.                 throw ie;      
  13.             }      
  14.             insert(e);      
  15.         } finally {      
  16.             lock.unlock();      
  17.         }      
  18. }      
 
[java] view plain copy
 
  1. public boolean offer(E e, long timeout, TimeUnit unit)      
  2.         throws InterruptedException {      
  3.      
  4.         if (e == nullthrow new NullPointerException();      
  5.     long nanos = unit.toNanos(timeout);      
  6.         final ReentrantLock lock = this.lock;      
  7.         lock.lockInterruptibly();      
  8.         try {      
  9.             for (;;) {      
  10.                 if (count != items.length) {      
  11.                     insert(e);      
  12.                     return true;      
  13.                 }      
  14.                 if (nanos <= 0)      
  15.                     return false;      
  16.                 try {      
  17.                 //如果没有被 signal/interruptes,需要等待nanos时间才返回      
  18.                     nanos = notFull.awaitNanos(nanos);      
  19.                 } catch (InterruptedException ie) {      
  20.                     notFull.signal(); // propagate to non-interrupted thread      
  21.                     throw ie;      
  22.                 }      
  23.             }      
  24.         } finally {      
  25.             lock.unlock();      
  26.         }      
  27.     }      
 
[java] view plain copy
 
  1. public boolean add(E e) {      
  2.     return super.add(e);      
  3. }      
  4. 父类:      
  5. public boolean add(E e) {      
  6.         if (offer(e))      
  7.             return true;      
  8.         else     
  9.             throw new IllegalStateException("Queue full");      
  10.     }    
 
该类中有几个实例变量:takeIndex/putIndex/count
[java] view plain copy
 
  1. 用三个数字来维护这个队列中的数据变更:      
  2.     /** items index for next take, poll or remove */     
  3.     private int takeIndex;      
  4.     /** items index for next put, offer, or add. */     
  5.     private int putIndex;      
  6.     /** Number of items in the queue */     
  7.     private int count;      
分享到:
评论

相关推荐

    Java多线程(五)之BlockingQueue深入分析

    Java多线程之BlockingQueue深入分析 Java多线程中,BlockingQueue是一种特殊的队列,它可以为线程同步提供有力的保障。在Java多线程(五)之BlockingQueue深入分析中,我们将深入分析BlockingQueue的定义、常用方法...

    BlockingQueue的使用

    本文将深入探讨BlockingQueue的使用、特性以及常见操作。 首先, BlockingQueue接口位于`java.util.concurrent`包下,它继承自`java.util.Queue`接口,并添加了一些阻塞操作。阻塞操作指的是当队列为空时,获取元素...

    10、阻塞队列BlockingQueue实战及其原理分析

    阻塞队列BlockingQueue是Java并发编程中一个重要的数据结构,它是线程安全的队列,主要用于生产者消费者模型中的数据交换。在Java的`java.util.concurrent`包中,提供了多种实现阻塞队列的类,如`ArrayBlockingQueue...

    基于java中BlockingQueue的使用介绍

    本文将深入探讨 BlockingQueue 的原理、特性以及如何在实际应用中使用。 ### 1. BlockingQueue概述 BlockingQueue 是一个并发容器,它实现了队列的接口,同时具备阻塞功能。当队列为空时,尝试从队列中获取元素的...

    spring MVC 初始启动blocking queue

    通过阅读和分析这些代码,你可以深入理解如何在Spring MVC项目中集成和利用`BlockingQueue`和`@PostConstruct`注解。 总结来说,`spring MVC 初始启动concurrent blocking queue`涉及的是在Spring MVC应用启动时...

    blockingqueue-example

    ### 三、 blockingqueue-example 示例项目分析 在 "blockingqueue-example-master" 示例项目中,我们可以看到如何使用 BlockingQueue 进行多线程交互。项目通常包含生产者(Producer)和消费者(Consumer)两个线程...

    Java 实例 - 生产者消费者问题源代码+详细指导教程.zip

    本实例提供了源代码和详细指导教程,帮助开发者深入理解这一概念。 生产者消费者问题通常使用Java中的`java.util.concurrent`包来解决,特别是`BlockingQueue`接口。在这个例子中,`BlockingQueue`作为共享的缓冲区...

    操作系统 生产者消费者问题 Java代码产者消费者问题,描述一组生产者向一组消费者提供产品.zip

    通过分析这些代码,可以更深入地理解多线程编程和Java并发机制。学习和理解这个问题对于进行高并发系统设计和优化是非常重要的,因为它是并发编程中常见的模式,广泛应用于消息队列、数据库连接池等场景。

    android自定义消息队列

    通过分析和实践`BlockingQueueDemo`,开发者可以深入理解Android中消息队列的工作原理,提高应用程序的响应性和可维护性。这种自定义的消息队列设计对于实现复杂的定时任务、动画控制或者其他需要精细控制的任务调度...

    java多线程编程起步

    本文将深入探讨Java多线程编程的基础知识,包括线程的创建、同步、通信以及相关实例。 一、线程的创建 在Java中,有两种主要的创建线程的方式: 1. 继承Thread类:创建一个新的类,继承自Thread类,然后重写它的...

    生产者消费者问题(JAVA版)

    通过这个实验,你可以深入理解Java并发编程中的同步与异步概念,以及`BlockingQueue`如何在生产者消费者问题中起到关键作用。此外,你还可以学习到如何在实际项目中使用Java的并发工具来提高多线程环境下的程序性能...

    BlockQueue练习

    在本练习中,我们将通过`BlockingQueue1.java`和`BlockingQueue2.java`两个文件来深入理解和实践BlockQueue的基本用法和实现。 BlockQueue的核心特性在于它的阻塞操作:当队列为空时,尝试获取元素的线程会被阻塞;...

    ProducerCustomer.zip

    首先,我们深入理解生产者消费者模型。该模型基于“缓冲区”概念,生产者将产品放入缓冲区,而消费者从缓冲区取出产品。当缓冲区满时,生产者需要等待;当缓冲区空时,消费者也需要等待。这种机制由Java的并发工具类...

    生产者消费者模型的演变

    在源码层面,我们可以通过分析`BlockingQueue`接口的实现,如`ArrayBlockingQueue`、`LinkedBlockingQueue`等,来了解其内部是如何处理线程的阻塞和唤醒的。这些实现通常会用到`wait()`和`notify()`方法,或者`Lock`...

    producer-consumer问题的分析和讨论

    《生产者-消费者问题的深度剖析与探讨》 在计算机科学和并发编程中,"生产者-消费者"问题是一个经典的问题模型,它涉及到多...通过对提供的代码文件的分析,我们可以深入理解这一模式在实际编程中的运用和实现细节。

    Java实现spooling假脱机技术

    通过对这些代码的学习和分析,可以帮助开发者深入理解Java模拟Spooling的具体实现方法。 通过以上讲解,我们可以看到Java虽然没有内置的Spooling机制,但借助其强大的并发库和数据结构,完全可以实现一个高效的假...

    生产者消费者问题---源码.rar

    生产者消费者问题是多线程编程中的一个经典案例,主要展示了线程间的同步和通信。...通过分析源码,我们可以深入理解如何利用`BlockingQueue`等工具解决这类问题,并学习到如何在多线程环境中确保程序的正确性和性能。

    深入浅出Java_Concurrency

    - **类库结构**:J.U.C提供了丰富的类库支持,包括但不限于`ExecutorService`、`Future`、`BlockingQueue`、`CountDownLatch`、`Semaphore`、`CyclicBarrier`等。 - **样例分析**:通过具体的代码示例来讲解这些类...

    【死磕Java集合】-集合源码分析.pdf

    Java集合框架源码分析 Java集合框架是Java语言中一个非常重要的组件,提供了多种数据结构和算法来存储和操作数据。在Java集合框架中,...本文对Java集合框架的源码进行了深入分析,为读者提供了详细的参考资料。

    模仿线程"生产者与消费者"的例子

    在这个"模仿线程"生产者与消费者"的例子中,我们将深入探讨这个经典的并发设计模式及其背后的原理。 生产者-消费者模式是一种典型的同步问题,用于解决数据生产与消费的异步处理。在这个模型中,生产者线程负责创建...

Global site tag (gtag.js) - Google Analytics