package study.java.collection.queue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; /** iterator()永远返回空 peek()永远返回null put()往queue放进去一个element以后就一直wait直到有其他thread进来把这个element取走 offer()往queue里放进一个element后立即返回,如果碰巧这个element被另一个thread取走了,offer方法返回ture, 认为offer成功,否则返回false offer(2000,TimeUnit.SECONDS)往queue里放一个element但是等待指定的时间后才返回,返回的逻辑和offer()方法一样。 take()取出并且remove掉queue里的element(认为是在queue里的),取不到东西他会一直等。 poll() 取出并且remove掉queue里的element(认为是在queue里的。。。),只有到碰巧另外一个线程正在往queue里offer 数据或者put数据的时候,该方法才会取到东西。否则立即返回null。 poll(2000, TimeUnit.SECONDS) 等待指定的时间然后取出并且remove掉queue里的element,其实就是再等其他的thread来往里塞。 isEmpty()永远是true。 remainingCapacity() 永远是0。 remove()和removeAll() 永远是false。 这是一个很有意思的阻塞队列,其中每个插入操作必须等待另一个线程的移除操作,同样任何一个移除操作都等待另一个线程的插入操作。 因此此队列内部其 实没有任何一个元素,或者说容量是0,严格说并不是一种容器。由于队列没有容量,因此不能调用peek操作,因为 只有移除元素时才有元素。 一个没有容量的并发队列有什么用了?或者说存在的意义是什么? SynchronousQueue 的实现非常复杂,当然了如果真要去分析还是能够得到一些经验的,但是前面分析了过多的结构后,发现越来 越陷于数据结构与算法里面了。我的初衷是通过研究并 发实现的原理来更好的利用并发来最大限度的利用可用资源。所以在后面的章节中 尽可能的少研究数据结构和算法,但是为了弄清楚里面的原理,必不可免的会涉及 到一些这方面的知识,希望后面能够适可而止。 再回到话题。SynchronousQueue 内部没有容量,但是由于一个插入操作总是对应一个移除操作,反过来同样需要满足。那么一个元 素就不会再SynchronousQueue 里面长时间停留,一旦有了插入线程和移除线程,元素很快就从插入线程移交给移除线程。也就是说 这更像是一种信道(管道),资源从一个方向快速传递到另一方 向。 需要特别说明的是,尽管元素在SynchronousQueue 内部不会“停留”,但是并不意味之SynchronousQueue 内部没有队列。 实际上SynchronousQueue 维护者线程队列,也就是插入线程或者移除线程在不同时存在的时候就会有线程队列。既然有队列,同 样就有公平性和非公平性特性,公平性保证正在等待的插入线 程或者移除线程以FIFO的顺序传递资源。 显然这是一种快速传递元素的方式,也就是说在这种情况下元素总是以最快的方式从插入着(生产者)传递给移除着(消费者),这在多任 务队列中是最快处理任务的方式。在线程池的相关章节中还会更多的提到此特性。 */ public class SynchronousQueueTest { public static void main(String[] args) throws InterruptedException { SynchronousQueue<String> sq = new SynchronousQueue<String>(); new Thread(new Runnable() { @Override public void run() { try { sq.put("abc"); Thread.sleep(10); sq.put("efg"); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); Thread.sleep(2000); new Thread(new Runnable() { @Override public void run() { try { System.out.println(sq.take()); System.out.println(sq.take()); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } }