Fork/Join模式(JSR166y)手记之TransferQueue/LinkedTransferQueue
来源:互联网 发布:淘宝图片水印带qq 编辑:程序博客网 时间:2024/05/21 05:56
TransferQueue是一个继承了 BlockingQueue的接口,并且增加若干新的方法。LinkedTransferQueue是实现类,其定义为一个无界的队列,一样具有先进先出(FIFO : first-in-first-out)的特性。
Doug Lea 这样评价它:
TransferQueue是一个聪明的队列,它是ConcurrentLinkedQueue, SynchronousQueue (在公平模式下), 无界的LinkedBlockingQueues等的超集。显然易见,混合了若干高级特性,并且具有高性能的一个组合体,一个多面手。
这里有一个有关LinkedTransferQueue的Doug Lea等人所撰写论文,讨论了其算法、性能等,地址:http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf
单纯从队列来看,TransferQueue接口增加了一些很实用的新特性,其transfer方法提供了线程之间直接交换对象的捷径,下面一一说来。
- transfer(E e)
若当前存在一个正在等待获取的消费者线程,即立刻移交之;否则,会插入当前元素e到队列尾部,并且等待进入阻塞状态,到有消费者线程取走该元素。 - tryTransfer(E e)
若当前存在一个正在等待获取的消费者线程(使用take()或者poll()函数),使用该方法会即刻转移/传输对象元素e;
若不存在,则返回false,并且不进入队列。
这是一个不阻塞的操作。 - tryTransfer(E e, long timeout, TimeUnit unit)
若当前存在一个正在等待获取的消费者线程,会立即传输给它;
否则将插入元素e到队列尾部,并且等待被消费者线程获取消费掉,
若在指定的时间内元素e无法被消费者线程获取,则返回false,同时该元素被移除。 - hasWaitingConsumer()
很明显,判断是否终端消费者线程 - getWaitingConsumerCount()
字面意思很明白,获取终端所有等待获取元素的消费线程数量 - size()
因为队列的异步特性,检测当前队列的元素个数需要逐一迭代,可能会得到一个不太准确的结果,尤其是在遍历时有可能队列发生更改。 - 批量操作
类似于 addAll,removeAll, retainAll, containsAll, equals, toArray 等方法,API不能保证一定会立刻执行。
因此,我们在使用过程中,不能有所期待,这是一个具有异步特性的队列。
注意事项:
- 无论是transfer还是tryTransfer方法,在>=1个消费者线程等待获取元素时(此时队列为空),都会立刻转交,这属于线程之间的元素交换。注意,这时,元素并没有进入队列。
- 在队列中已有数据情况下,transfer将需要等待前面数据被消费掉,直到传递的元素e被消费线程取走为止。
- 使用transfer方法,工作者线程可能会被阻塞到生产的元素被消费掉为止
- 消费者线程等待为零的情况下,各自的处理元素入队与否情况有所不同。
- size()方法,需要迭代,可能不太准确,尽量不要调用。
或许,下次我们在构造一个线程池时,可以考虑使用TransferQueue:
public static ExecutorService newTransferCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new LinkedTransferQueue()); }
简单测试代码:
package com.learn.jsry166y.demo.queue;import java.util.concurrent.TimeUnit;import jsr166y.LinkedTransferQueue;import jsr166y.Phaser;import jsr166y.TransferQueue;import junit.framework.Assert;import org.junit.Test;/*** 测试LinkedTransferQueue的一些特性** @author yongboy* @time 2012-2-1* @version 1.0*/public class TestTransferQueue {final static TransferQueue<String> queue = new LinkedTransferQueue<String>();// 模拟transfer等待消费者线程,若消费者线程不出现的话,则阻塞@Testpublic void testTransfer() {try {// 优先启动一个线程,做消费者线程,去取队列数据new Thread() {@Overridepublic void run() {try {Thread.sleep(5000L);} catch (InterruptedException e) {e.printStackTrace();}try {// 取完元素,transfer不再阻塞String result = queue.take();System.out.println("result : " + result);} catch (InterruptedException e) {e.printStackTrace();}}}.start();queue.transfer("hello0");System.out.println("the data had been taked");} catch (InterruptedException e1) {e1.printStackTrace();}Assert.assertEquals(queue.size(), 0);}// 模拟若消费者线程等待获取元素,元素不存在情况下,进入阻塞状态@Testpublic void testTake() {try {// 优先启动一个线程,做消费者线程,去取队列数据new Thread() {@Overridepublic void run() {try {long start = System.currentTimeMillis();// 取完元素,transfer不再阻塞String result = queue.take();System.out.println("result : " + result+ " use time : "+ (System.currentTimeMillis() - start));} catch (InterruptedException e) {e.printStackTrace();}}}.start();Thread.sleep(2000L);queue.transfer("hello-0");} catch (InterruptedException e1) {e1.printStackTrace();}Assert.assertEquals(queue.size(), 0);}// 模拟获取等待消费者线程的个数@Testpublic void testWaitingConsumerCount() {int consumerCount = -1;int threadNum = 5;try {for (int i = 0; i < threadNum; i++) {new Thread() {@Overridepublic void run() {try {long start = System.currentTimeMillis();String result = queue.take();System.out.println("result : " + result+ " use time : "+ (System.currentTimeMillis() - start));} catch (InterruptedException e) {e.printStackTrace();}}}.start();}Thread.sleep(2000L);consumerCount = queue.getWaitingConsumerCount();for (int i = 0; i < consumerCount; i++) {queue.transfer("hello-0-" + i);}} catch (InterruptedException e1) {e1.printStackTrace();}Assert.assertEquals(consumerCount, threadNum);}@Testpublic void testTryTransfer() {queue.tryTransfer("hello");try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}Assert.assertEquals(queue.size(), 0);}@Testpublic void testTryTimedTransfer() {try {queue.tryTransfer("hello2", 100L, TimeUnit.MILLISECONDS);} catch (InterruptedException e1) {e1.printStackTrace();}try {Thread.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}Assert.assertEquals(queue.size(), 0);}@Testpublic void testAdd() {queue.add("hello3");Assert.assertEquals(queue.size(), 1);}@Testpublic void testGet() {String result = queue.poll();Assert.assertEquals(result, "hello3");}// 如何模拟,在队列有数据的情况下,测试transfer@Testpublic void testTransferWithOldElement() {final int COUNT = 1001;final Phaser barrier = new Phaser(COUNT);final StringBuilder sb = new StringBuilder();try {for (int i = 0; i < 999; i++) {queue.add("hello_0_" + i);}for (int i = 0; i < 1000; i++) {// 优先启动一个线程,做消费者线程,去取队列数据new Thread() {@Overridepublic void run() {try {barrier.arriveAndAwaitAdvance();// 取完元素,transfer不再阻塞String result = queue.take();if (result.startsWith("_hello_")) {System.out.println("thread name : "+ Thread.currentThread().getName()+ " ; queue size : " + queue.size());sb.append(result);// 模拟主线程等待时间Thread.sleep(1000L);// 终止,主线程得以继续barrier.forceTermination();}} catch (InterruptedException e) {e.printStackTrace();}}}.start();}barrier.arriveAndAwaitAdvance();queue.transfer("_hello_");} catch (Exception e1) {e1.printStackTrace();}long start = System.currentTimeMillis();barrier.arriveAndAwaitAdvance();System.out.println("wait use time : "+ (System.currentTimeMillis() - start));Assert.assertEquals(sb.toString(), "_hello_");}}
- Fork/Join模式(JSR166y)手记之TransferQueue/LinkedTransferQueue
- Fork/Join框架之Fork、Join操作
- Fork/Join框架之Fork、Join操作
- Fork/Join框架之Fork、Join操作
- jdk7之fork-join
- JDK7中的Fork/Join模式
- Java 多线程之 TransferQueue
- 阻塞队列之LinkedTransferQueue
- Fork/join框架之ForkJoinPool
- Java多线程之Fork/Join
- Fork/join框架之ForkJoinPool
- java多线程之fork/join
- TransferQueue
- LinkedTransferQueue
- JDK 7 中的 Fork/Join 模式
- JDK 7 中的 Fork/Join 模式
- JDK 7 中的 Fork/Join 模式
- JDK 7 中的 Fork/Join 模式
- setsockopt详解
- 转载识别网络爬虫
- Java算法排序之--选择排序
- Android发送post请求
- 再说dfs.umask
- Fork/Join模式(JSR166y)手记之TransferQueue/LinkedTransferQueue
- Launcher介绍总结(二)
- WebRTC音视频引擎研究(1)--整体架构分析 .
- weblogic注册为windows系统服务的一个问题
- memcmp,memicmp函数
- shell的几个实用快捷键
- URLEncoder.encode与URLDecoder.docode的使用
- 三款常见JSON类库工具性能对比
- 关于递归的基本认识