欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    Java并发编程实践-电子书-03章.pdf

    • 资源ID:70321949       资源大小:479.92KB        全文页数:53页
    • 资源格式: PDF        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    Java并发编程实践-电子书-03章.pdf

    第三章 使用第三章 使用 JDK 并发包构建程序并发包构建程序 第三章 使用JDK并发包构建程序.1 3.1 java.util.concurrent概述.2 3.2 原子量.2 3.2.1 锁同步法.3 3.2.2 比较并交换.4 3.2.3 原子变量类.6 3.2.4 使用原子量实现银行取款.8 3.3 并发集合.12 3.3.1 队列Queue与BlockingQueue.12 3.3.2 使用 ConcurrentMap 实现类.19 3.3.3 CopyOnWriteArrayList和CopyOnWriteArraySet.20 3.4 同步器.21 3.4.1 Semaphore.21 3.4.2 Barrier.24 3.4.3 CountDownLatch.27 3.4.4 Exchanger.29 3.4.5 Future和FutureTask.31 3.5 显示锁.33 3.5.1 ReentrantLock.33 3.5.1.1 ReentrantLock的特性.34 3.5.1.2 ReentrantLock性能测试.38 3.5.2 ReadWriteLock.42 3.6 Fork-Join框架.46 3.6.1 应用Fork-Join.47 3.6.2 应用ParallelArray.51 参考文献.52 3.1 java.util.concurrent 概述概述 JDK5.0 以后的版本都引入了高级并发特性,大多数的特性在 java.util.concurrent 包中,是专门用于多线并发编程的,充分利用了现代多处理器和多核心系统的功能以编写大规模并发应用程序。主要包含原子量、并发集合、同步器、可重入锁,并对线程池的构造提供了强力的支持。原子量是定义了支持对单一变量执行原子操作的类。所有类都有 get 和 set 方法,工作方法和对 volatile 变量的读取和写入一样。并发集合是原有集合框架的补充,为多线程并发程序提供了支持。主要有:BlockingQueue,ConcurrentMap,ConcurrentNavigableMap。同步器提供了一些帮助在线程间协调的类,包括 semaphores,barriers,latches,exchangers 等。一般同步代码依靠内部锁(隐式锁),这种锁易于使用,但是有很多局限性。新的 Lock对象支持更加复杂的锁定语法。和隐式锁类似,每一时刻只有一个线程能够拥有 Lock 对象,通过与其相关联的 Condition 对象,Lock 对象也支持 wait 和 notify 机制。线程完成的任务(Runnable 对象)和线程对象(Thread)之间紧密相连。适用于小型程序,在大型应用程序中,把线程管理和创建工作与应用程序的其余部分分离开更有意义。线程池封装线程管理和创建线程对象。线程池在第一章已经讲过,不再赘述。3.2 原子量原子量 近来关于并发算法的研究主要焦点是无锁算法(nonblocking algorithms),这些无锁算法使用低层原子化的机器指令,例如使用compare-and-swap(CAS)代替锁保证并发情况下数据的完整性。无锁算法广泛应用于操作系统与JVM中,比如线程和进程的调度、垃圾收集、实现锁和其他并发数据结构。在 JDK5.0 之前,如果不使用本机代码,就不能用 Java 语言编写无等待、无锁定的算法。在 java.util.concurrent 中添加原子变量类之后,这种情况发生了变化。本节了解这些新类开发高度可伸缩的无阻塞算法。要使用多处理器系统的功能,通常需要使用多线程构造应用程序。但是正如任何编写并发应用程序的人可以告诉你的那样,要获得好的硬件利用率,只是简单地在多个线程中分割工作是不够的,还必须确保线程确实大部分时间都在工作,而不是在等待更多的工作,或等待锁定共享数据结构。如果线程之间不需要协调,那么几乎没有任务可以真正地并行。以线程池为例,其中执行的任务通常相互独立。如果线程池利用公共工作队列,则从工作队列中删除元素或向工作队列添加元素的过程必须是线程安全的,并且这意味着要协调对头、尾或节点间链接指针所进行的访问。正是这种协调导致了所有问题。3.2.1 锁同步法锁同步法 在 Java 语言中,协调对共享字段访问的传统方法是使用同步同步,确保完成对共享字段的所有访问,同时具有适当的锁定。通过同步,可以确定(假设类编写正确)具有保护一组访问变量的所有线程都将拥有对这些变量的独占访问权,并且以后其他线程获得该锁定时,将可以看到对这些变量进行的更改。弊端是如果锁定锁定竞争太厉害(线程常常在其他线程具有锁定时要求获得该锁定),会损害吞吐量,因为竞争的同步非常昂贵。对于现代 JVM 而言,无竞争的同步现在非常便宜。基于锁的算法的另一个问题是:如果延迟具有锁的线程(因为页面错误、计划延迟或其他意料之外的延迟),则没有要求获的锁的线程可以继续运行。还可以使用 volatile 变量来以比同步更低的成本存储共享变量,但它们有局限性。虽然可以保证其他变量可以立即看到对 volatile 变量的写入,但无法呈现原子操作的读-修改-写顺序,这意味着 volatile 变量无法用来可靠地实现互斥(互斥锁定)或计数器。下面以实现一个计数器为例。通常情况下一个计数器要保证计数器的增加,减少等操作需要保持原子性,使类成为线程安全的类,从而确保没有任何更新信息丢失,所有线程都看到计数器的最新值。使用内部锁实现的同步代码一般如下:package jdkapidemo;public class SynchronizedCounter private int value;public synchronized int getValue()return value;public synchronized int increment()return+value;public synchronized int decrement()return-value;increment()和 decrement()操作是原子的读-修改-写操作,为了安全实现计数器,必须使用当前值,并为其添加一个值,或写出新值,所有这些均视为一项操作,其他线程不能打断它。否则,如果两个线程试图同时执行增加,操作的不幸交叉将导致计数器只被实现了一次,而不是被实现两次。(注意,通过使值变量成为 volatile 变量并不能可靠地完成这项操作。)计数器类可以可靠地工作,在竞争很小或没有竞争时都可以很好地执行。然而,在竞争激烈时,这将大大损害性能,因为 JVM 用了更多的时间来调度线程,管理竞争和等待线程队列,而实际工作(如增加计数器)的时间却很少。使用锁,如果一个线程试图获取其他线程已经具有的锁,那么该线程将被阻塞,直到该锁可用。此方法具有一些明显的缺点,其中包括当线程被阻塞来等待锁时,它无法进行其他任何操作。如果阻塞的线程是高优先级的任务,那么该方案可能造成非常不好的结果(称为 优先级倒置的危险)。使用锁还有一些其他危险,如死锁(当以不一致的顺序获得多个锁时会发生死锁)。甚至没有这种危险,锁也仅是相对的粗粒度协调机制,同样非常适合管理简单操作,如增加计数器或更新互斥拥有者。如果有更细粒度的机制来可靠管理对单独变量的并发更新,则会更好一些;在大多数现代处理器都有这种机制。3.2.2 比较并交换比较并交换 大多数现代处理器都包含对多处理的支持。当然这种支持包括多处理器可以共享外部设备和主内存,同时它通常还包括对指令系统的增加来支持多处理的特殊要求。特别是,几乎每个现代处理器都有通过可以检测或阻止其他处理器的并发访问的方式来更新共享变量的指令指令。现在的处理器(包括 Intel 和 Sparc 处理器)使用的最通用的方法是实现名为“比较并交换(Compare And Swap)”或 CAS 的原语。(在 Intel 处理器中,比较并交换通过cmpxchg 系列指令实现。PowerPC 处理器有一对名为“加载并保留”和“条件存储”的指令,它们实现相同的目地;MIPS 与 PowerPC 处理器相似,除了第一个指令称为“加载链接”。)CAS 操作包含三个操作数 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”通常将 CAS 用于同步的方式是从地址 V 读取值 A,执行多步计算来获得新值 B,然后使用 CAS 将 V 的值从 A 改为 B。如果 V 处的值尚未同时更改,则 CAS 操作成功。类似于 CAS 的指令允许算法执行读-修改-写操作,而无需害怕其他线程同时修改变量,因为如果其他线程修改变量,那么 CAS 会检测它(并失败),算法可以对该操作重新计算。下面的程序说明了 CAS 操作的行为(而不是性能特征),但是 CAS 的价值是它可以在硬件中实现,并且是极轻量级的(在大多数处理器中)。后面我们分析 Java 的源代码可以知道,JDK 在实现的时候使用了本地代码。下面的代码说明 CAS 的工作原理(为了便于说明,用同步语法表示)。package jdkapidemo;public class SimulatedCAS private int value;public synchronized int getValue()return value;public synchronized int compareAndSwap(int expectedValue,int newValue)if(value=expectedValue)value=newValue;return value;基于 CAS 的并发算法称为“无锁定算法”,因为线程不必再等待锁定(有时称为互斥或关键部分,这取决于线程平台的术语)。无论 CAS 操作成功还是失败,在任何一种情况中,它都在可预知的时间内完成。如果 CAS 失败,调用者可以重试 CAS 操作或采取其他适合的操作。下面的代码显示了重新编写的计数器类来使用 CAS 替代锁定:package jdkapidemo;public class CasCounter private SimulatedCAS value;public int getValue()return value.getValue();public int increment()int oldValue=value.getValue();while(pareAndSwap(oldValue,oldValue+1)!=oldValue)oldValue=value.getValue();return oldValue+1;如果每个线程在其他线程任意延迟(或甚至失败)时都将持续进行操作,就可以说该算法是保证每个线程在其有限的步骤中正确计算自己的操作,而不管其他线程的操作、计时、交叉 CasCounter.increment()成增加。15 年里,人们已经对无等待且无锁算法(也称为无阻塞算法无阻塞算法)进行了大量研究,许多人通用数据结构已经发现了无阻塞算法。无阻塞算法被广泛用于操作系统和 JVM 细的粒度级别,允许更高程度的并行机制等等。3.2.3 原子变量类原子变量类 java.util.concurrent.atomic 包中添加原子变量类。所有原子变量类都公开“比较并设置比较并设置”原语原语语都是使用平台上可用的最快本机结构(比较并交换、供了原子变量的 9 种风格(AtomicInteger、AtomicLong、olean、原子整型、长型、及原子标记引用和戳记引用类的数组形式,。volatilevolatile条件的比较并设置更新。读取和写入原子变量与读取和写入对tile 变量的访问具有相同“无等待”无等待”的。“无锁定算法”“无锁定算法”要求某个线程总是执行操作。(无等待的另一种定义是或速度。这一限制可以是系统中线程数的函数;例如,如果有 10 个线程,每个线程都执行一次操作,最坏的情况下,每个线程将必须重试最多九次,才能完)再过去的级别,进行诸如线程和进程调度等任务。虽然它们的实现比较复杂,但相对于基于锁的备选算法,它们有许多优点:可以避免优先级倒置和死锁等危险,竞争比较便宜,协调发生在更(与比较并交换类似),这些原加载链接/条件存储,最坏的情况下是旋转锁)来实现的。java.util.concurrent.atomic 包中提AtomicReference、AtomicBo引用、其原子地更新一对值)原子变量类可以认为是变量的泛化,它扩展了变量的概念,来支持原子vola的存取语义。虽然原子变量类表面看起来与 SynchronizedCounter 例子一样,但相似仅是表面的。在表面之下,原子变量的操作会变为平台提供的用于并发访问的硬件原语,比如比较并交换。更多 调整具有竞争的并发应用程序的可伸缩性的通用技术是降低使用的锁对象的粒度,希望的锁请求从竞争变为不竞争。从锁转换为原子变量可以获得相同的结果,通过切换为更细粒度的协调机制,竞争的操作就更少,从而提高了吞吐量。下面的程序是使用原子变量后的计数器:package jdkapidemo;import java.util.concurrent.atomic.AtomicInteger;public class AtomicCounter private AtomicInteger value=new AtomicInteger();public int getValue()return value.get();public int increment()return value.incrementAndGet();public int increment(int i)return value.addAndGet(i);public int decrement()return value.decrementAndGet();public int decrement(int i)return value.addAndGet(-i);下面写一个测试类:package jdkapidemo;public class AtomicCounterTest extends Thread AtomicCounter counter;public AtomicCounterTest(AtomicCounter counter)this.counter=counter;Override public void run()int i=counter.increment();System.println(generated outnumber:+i);public stat void main(String args)ic AtomicCounter counter=new AtomicCounter();for(int i=0;i=money)try Thread.sleep(delay);balance=balance-money;System.out.println(Thread.currentThread().getName()+withdraw +money+successful!+balance);catch(InterruptedException e)else System.out.println(Thread.currentThread().getName()+balance is not enough,withdraw failed!+balance);为了测试帐户类,定义一个测试类 package jdkapidemo.bank;public class AccountThread extends Thread Account account;int delay;public AccountThread(Account acount,int delay)this.account=acount;this.delay=delay;public void run()account.withdraw(100,delay);public static void main(String args)Account acount=new Account(100);AccountThread acountThread1=new AccountThread(acount,1000);AccountThread acountThread2=new AccountThread(acount,0);acountThread1.start();acountThread2.start();运行结果如下:Totle Money:100.0 Thread-1 withdraw 100.0 successful!0.0 Thread-0 withdraw 100.0 successful!-100.0 从运行结果可以看出,总额 100 元,使用两个线程同时取钱,都成功,最后帐户余额为-100。nce money”这条语句时,balance的实以使用 synchronized 关键字。修改如下:元,表现为透支,这样破坏了数据的完整性从程序可以看出 withdrawal 方法包含了余额判断语句,为什么还会发生数据的一致性被破坏呢?因多线程并发,当执行“balance=bala际值已经不是先前的值。按照正确的业务逻辑,需要保证在一个取款操作结束时,不能执行另一个取款操作,需要把 withdraw 同步起来,我们可public synchronized void withdraw(double money,int delay)运行修改后的程序,结果如下:Totle Money:100.0 Thread-1 withdraw 100.0 successful!0.0 Thread-0balance is not enough,withdraw failed!0.0 前面我们讲过了原子量的使用,现在修改 balance 为原子量。用原子量的特性实现取款操作的原子性。把原来方法的修改语句“balance=balance money”修改为“ba把 Account 类修为 AtomicAccount,把 balance 定义为 AtomicLong 类型,然后修改withdraw 方法,pareAndSet(oldvalue,oldvalue-money)”,这个方法在执行的时候是原子化的,首先比较所读取的值是否和被修改的值一致,如果一致则执行原子化修改,否则失败。如果帐余额在读取之后,被修改了,则 compareAndSet 会返回 FALSE,则余额修改失败,不能完成取款操作。package jdkapidemo.bank;import java.util.concurrent.atomic.AtomicLong;public class AtomicAccount AtomicLong balance;public AtomicAccount(long money)balance=new AtomicLong(money);System.out.println(Totle Money:+balance);public void deposit(long money)balance.addAndGet(money);public void withdraw(long money,int delay)long oldvalue=balance.get();if(oldvalue=money)try Thread.sleep(delay);catch(InterruptedException e)e.printStackTrace();if(pareAndSet(oldvalue,oldvalue-money)System.out.println(Thread.currentThread().getName()+withdraw +money+successful!+balance);else System.out.println(Thread.currentThread().getName()+thread concurrent,withdraw failed!+balance);else System.out.println(Thread.currentThread().getName()+balance is not enough,withdraw failed!+balance);public long get()return balance.get();重新定义测试类:package jdkapidemo.bank;public class AtomicAccountTest extends Thread AtomicAccount account;int delay;public AtomicAccountTest(AtomicAccount account,int delay)this.account=account;this.delay=delay;public void run()account.withdraw(100,delay);public static void main(String args)AtomicAccount account=new AtomicAccount(100);AtomicAccountTest accountThread1=new AtomicAccountTest(account,1000);AtomicAccountTest accountThread2=new AtomicAccountTest(account,0);accountThread1.start();accountThread2.start();运行结果如下:Totle Money:100 Thread-1 withdraw 100 successful!0 Thread-0 thread concurrent,withdraw failed!0 从运行结果可以看出,两个线程在执行 withdraw 方法时,开始余额比较都是成功的,随后e-money)原子方法,这个在更新余额是我们使用了 pareAndSet(oldvalue,oldvalu方法在修改余额值之前还要比较所读取的值是否和被修改的值一致比较所读取的值是否和被修改的值一致,如果一致则修改,如果不一致则修改失败,返回 false。并且保证在修改的过程是原子性的,不会被中断。大多数用户都不太可能自己使用原子变量开发无阻塞算法,他们更可能使用 java.util.concurrent 中提供的版本,如 ConcurrentLinkedQueue。但是万一您想知道对比以前 JDK些变量。ava.util.concurrent 中的类基于这些低级原子变量工架中新的 Queue 接口、这个接口的非并发和并发实现、并发 Map实现和专用于读操作大大超过写操作这种情况的并发 List 和 Set 实现。til.Queue。虽然肯定可以在相对应的两端进行添加和删除而将 java.util.List 作为队列对待,但是这个新的 Queue 接口提供了支持添可用的空间,则抛出 IllegalStateException。入元移除此队列的头,如果此队列为空,则返回 null。此队列为空时将抛出一个异常。中的相类似的功能,这些类的性能是如何改进的,可以使用通过原子变量类公开的细粒度、硬件级别的并发原语。开发人员可以直接将原子变量用作共享计数器、序号生成器和其他独立共享变量的高性能替代,否则必须通过同步保护这通过内部公开新的低级协调原语,和提供一组公共原子变量类,现在用 Java 语言开发无等待、无锁定算法首次变为可行。然后,j具构建,为它们提供比以前执行相似功能的类更显著的可伸缩性优点。虽然您可能永远不会直接使用原子变量,还是应该为它们的存在而欢呼。3.3 并发集合并发集合 我们将探讨集合框3.3.1 队列队列 Queue 与与 BlockingQueue java.util 包为集合提供了一个新的基本接口:java.u加、删除和检查集合的更多方法。1)boolean add(Object e):将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true,如果当前没有2)public boolean offer(Object element):将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插素,而只是抛出一个异常。3)public Object remove():获取并移除此队列的头。4)public Object poll();获取并5)public Object element();获取但是不移除此队列的头6)public Object peek();获取但不移除此队列的头;如果此队列为空,则返回 null。基本上,一个队列就是一个先入先出(FIFO)的数据结构。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。这时新的 offer 方法就可以起 Queue 接口。可以将 LinkedList 集合看成这两者中的任何作用了。它不是对调用 add()方法抛出一个 unchecked 异常,而只是得到由 offer()方法方法 返回的 false。remove()和 poll()方法都是从队列中删除第一个元素(head)。remove()的行为与 Collection 接口的版本相似,但是新的 poll()方法方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。后两个方法 element()和 peek()用于在队列的头部查询元素。与 remove()方法类似,在队列为空时,element()抛出一个异常,而 peek()返回 null。在 JDK 中有两组 Queue 实现:实现了新 BlockingQueue 接口的和没有实现这个接口的。我将首先分析那些没有实现的。在最简单的情况下,原来有的 java.util.LinkedList 实现已经改造成不仅实现 java.util.List 接口,而且还实现 java.util.一种。下面的程序将显示把 LinkedList 作为 Queue 的使用方法:package queuedemo;import java.util.LinkedList;import java.util.Queue;public class QueueTest public static void main(String args)Queue queue=new LinkedList();queue.offer(One);queue.offer(Two);queue.offer(Three);queue.offer(Four);System.out.println(Head of queue is:+queue.poll();输出结果为:Head of queue is:One PriorityQueue ConcurrentLinkedQueue 类在 Collection Framework 中加入两个具体集合实质上维护了一个有序列表。加入到 Queue 中的元素根据它们的天然和实现。PriorityQueue 类排序(通过其 java.util.Comparable 实现)或者根据传递给构造函数的 java.util.Comparator 实现来定位。将上面程序中的 LinkedList 改变为 PriorityQueue 将会打印出 Four 而不是 One,因为按字母排列,即字符串的天然顺序,Four 是第一个。ConcurrentLinkedQueue 是基于链接节点的、线程安全的队列。并发访问不需要同步。因为它在队列的尾部添加元素并从头部删除它们,所以只要不需要知道队列的大小,ConcurrentLinkedQueue 对公共集合的共享访问就可以工作得很好。收集关于队列大小的信息会很慢,需要遍历队列。package queuedemo;import java.util.PriorityQueue;import java.util.Queue;public class PriorityQueueDemo public static void main(String args)Queue queue=new PriorityQueue();queue.offer(One);queue.offer(Two);queue.offer(Three);queue.offer(Four);System.out.println(Head of queue is:+queue.poll();输出结果如下:Head of queue is:Four current 包可用的具体集合类中加入了 BlockingQueue 接口和五个阻塞队列类。阻塞队列实质上就是一种带有一点扭曲的 FIFO 数据结构,不是立即从队列中添加或 链接节点支持的可选有界队列。级队列。ezvous)机制。下面以 ArrayBlockingQueue 为例写一个程序,表示生产者-消费者问题。生产者向阻塞新的 java.util.con者删除元素,线程执行操作被阻塞,直到有空间或者元素可用。BlockingQueue 接口的 Javadoc 给出了阻塞队列的基本用法,生产者中的 put()操作会在没有空间可用时阻塞,而消费者的 take()操作会在队列中没有任何东西时阻塞。五个队列所提供的各有不同:ArrayBlockingQueue:一个由数组支持的有界队列。LinkedBlockingQueue:一个由PriorityBlockingQueue:一个由优先级堆支持的无界优先DelayQueue:一个由优先级堆支持的、基于时间的调度队列。SynchronousQueue:一个利用 BlockingQueue 接口的简单聚集(rend 队列中放入字符,消费者从阻塞队列中移除字符。package queuedemo;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;public class BlockingQueueDemo public static void main(String args)BlockingQueue queue=new ArrayBlockingQueue(5);Producer p=new Producer(queue);Consumer c1=new Consumer(queue);Consumer c2=new Consumer(queue);new Thread(p).start();new Thread(c1).start();new Thread(c2).start();class Producer implements Runnable private final BlockingQueue queue;Producer(BlockingQueue q)queue=q;public void run()try for(int i=0;i 100;i+)queue.put(produce();catch(InterruptedException ex)ex.printStackTrace();String produce()String temp=+(char)(A+(int)(Math.random()*26);System.out.println(produce +temp);return temp;class Consumer implements Runnable private final BlockingQueue queue;Consumer(BlockingQueue q)queue=q;public void run()try for(int i=0;i 100;i+)consume(queue.take();catch(InterruptedException ex)ex.printStackTrace();void consume(String x)System.out.println(consume +x);输出结果如下:produce W produce S produce D produce Q consume S consume W consume Q consume D produce V produce J produce P produce A consume V consume P produce I consume J consume I produce C.前两个类 ArrayBlockingQueue 和 LinkedBlockingQueue 几乎相同,只是在后备存储器方 面 有 所 不 同,LinkedBlockingQueue 并 不 总 是 有 容 量 界 限。无 大 小 界 限 的 Link看作 TreeSet 的可能替代物。例如,在队列中加入字素必须实现新的 Delayed 接口(只有一个方法 long getDelay(java.util.concurrent.TimeUnit edBlockingQueue 类在添加元素时永远不会有阻塞队列的等待(至少在其中有 Integer.MAX_VALUE 元素之前不会)。PriorityBlockingQueue 是具有无界限容量的队列,它利用所包含元素的 Comparable 排序顺序来以逻辑顺序维护元素。可以将它符串 One、Two、Three 和 Four 会导致 Four 被第一个取出来。对于没有天然顺序的元素,可以为构造函数提供一个 Comparator。不过对 PriorityBlockingQueue 有一个技巧。从 iterator()返回的 Iterator 实例不需要以优先级顺序返回元素。如果必须以优先级顺序遍历 所 有 元 素,那 么 让 它 们 都 通 过 toArray()方 法 并 自 己 对 它 们 排 序,像 Arrays.sort(pq.toArray()。新的 DelayQueue 实现可能是其中最有意思(也是最复杂)的一个。加入到队列中的元unit))。因为队列的大小没有界限,使得添加可以立即返回,但是在延迟时间过去之前,不能从队列中取出元素。如果多个元素完成了延迟,那么最早失效/失效时间最长的元素将第一个取出。实际上没有听上去这样复杂。下面的程序演示了这种新的阻塞队列集合的使用:package queuedemo;import java.util.Random;import java.util.concurrent.DelayQueue;import java.util.concurrent.Delayed;import java.util.concurrent.TimeUnit;public class DelayQueueDemo static class NanoDelay implements Delayed long trigger;NanoDelay(long i)trigger=System.nanoTime()+i;public boolean equals(Object other)return(

    注意事项

    本文(Java并发编程实践-电子书-03章.pdf)为本站会员(asd****56)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开