LinkedTransferQueue在JDK7 中新增的。无界FIFO线程安全的阻塞队列。
transfer 算法比较复杂,实现很难看明白。大致的理解是采用所谓双重数据结构 (dual data structures) 。之所以叫双重,其原因是方法都是通过两个步骤完成:保留与完成。比如消费者线程从一个队列中取元素,发现队列为空,他就生成一个空元素放入队列 , 所谓空元素就是数据项字段为空。然后消费者线程在这个字段上旅转等待。这叫保留。直到一个生产者线程意欲向队例中放入一个元素,这里他发现最前面的元素的数据项字段为 NULL,他就直接把自已数据填充到这个元素中,即完成了元素的传送。大体是这个意思,这种方式优美了完成了线程之间的高效协作。
构造方法
public LinkedTransferQueue() {
}
public LinkedTransferQueue(Collection<? extends E> c) {
this();
addAll(c);
}
常用方法
tryTransfer:
/**
* 不阻塞
* @return true 有 消费者 等待消费
* @return false 无 消费者 等待消费
*/
@Test
public void tryTransfer() {
boolean b = queue.tryTransfer(1);
System.out.println(b);
}
transfer:
/**
* transfer,阻塞,直到有消费者消费,才能插入
* 注意:只能消费,不能使用peek等(peek只是取出,并未消费),不然一直等待
*
* take:一直阻塞
* poll: 不阻塞,拿不到值,返回null
*
* 还有个重载:tryTransfer(E e, long timeout, TimeUnit unit)
*/
@Test
public void transfer() throws InterruptedException {
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.schedule(new Runnable() {
@Override
public void run() {
try {
System.out.println(queue.take());
} catch (Exception e) {
e.printStackTrace();
}
}
}, 2, TimeUnit.SECONDS);
queue.transfer(1);
// System.out.println("----" + queue.size());
}
/**
* add offer put 这三个方法都是调用xfer(e, true, ASYNC, 0)
* 只能return不一样,都是直接插值,无阻塞
* @throws InterruptedException
*/
@Test
public void addofferput() throws InterruptedException {
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.schedule(new Runnable() {
@Override
public void run() {
try {
System.out.println(queue.take());
} catch (Exception e) {
e.printStackTrace();
}
}
}, 2, TimeUnit.SECONDS);
queue.add(1);
System.out.println("--=====--" + queue.size());
queue.offer(2);
System.out.println("--=====--" + queue.size());
queue.put(3);
System.out.println("--=====--" + queue.size());
TimeUnit.SECONDS.sleep(3);
System.out.println("--=====--" + queue.size());
}