阻塞队列:线程安全
按 FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
注意:
1、必须要使用take()方法在获取的时候达成阻塞结果
2、使用poll()方法将产生非阻塞效果
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class BlockingDeque {
//阻塞队列,FIFO
private static LinkedBlockingQueue<Integer> concurrentLinkedQueue = new LinkedBlockingQueue<Integer>();
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(</span><span style="color:#0000ff;">new</span> Producer(<span style="color:#800000;">"</span><span style="color:#800000;">producer1</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Producer(<span style="color:#800000;">"</span><span style="color:#800000;">producer2</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Producer(<span style="color:#800000;">"</span><span style="color:#800000;">producer3</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Consumer(<span style="color:#800000;">"</span><span style="color:#800000;">consumer1</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Consumer(<span style="color:#800000;">"</span><span style="color:#800000;">consumer2</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Consumer(<span style="color:#800000;">"</span><span style="color:#800000;">consumer3</span><span style="color:#800000;">"</span><span style="color:#000000;">));
}
static class Producer implements Runnable {
private String name;
</span><span style="color:#0000ff;">public</span><span style="color:#000000;"> Producer(String name) {
</span><span style="color:#0000ff;">this</span>.name =<span style="color:#000000;"> name;
}
</span><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span><span style="color:#000000;"> run() {
</span><span style="color:#0000ff;">for</span> (<span style="color:#0000ff;">int</span> i = <span style="color:#800080;">1</span>; i < <span style="color:#800080;">10</span>; ++<span style="color:#000000;">i) {
System.</span><span style="color:#0000ff;">out</span>.println(name+ <span style="color:#800000;">"</span><span style="color:#800000;"> 生产: </span><span style="color:#800000;">"</span> +<span style="color:#000000;"> i);
</span><span style="color:#008000;">//</span><span style="color:#008000;">concurrentLinkedQueue.add(i); </span>
<span style="color:#0000ff;">try</span><span style="color:#000000;"> {
concurrentLinkedQueue.put(i);
Thread.sleep(</span><span style="color:#800080;">200</span>); <span style="color:#008000;">//</span><span style="color:#008000;">模拟慢速的生产,产生阻塞的效果</span>
} <span style="color:#0000ff;">catch</span><span style="color:#000000;"> (InterruptedException e1) {
</span><span style="color:#008000;">//</span><span style="color:#008000;"> TODO Auto-generated catch block</span>
e1.printStackTrace();
}
}
}
}
static class Consumer implements Runnable {
private String name;
</span><span style="color:#0000ff;">public</span><span style="color:#000000;"> Consumer(String name) {
</span><span style="color:#0000ff;">this</span>.name =<span style="color:#000000;"> name;
}
</span><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span><span style="color:#000000;"> run() {
</span><span style="color:#0000ff;">for</span> (<span style="color:#0000ff;">int</span> i = <span style="color:#800080;">1</span>; i < <span style="color:#800080;">10</span>; ++<span style="color:#000000;">i) {
</span><span style="color:#0000ff;">try</span><span style="color:#000000;"> {
</span><span style="color:#008000;">//</span><span style="color:#008000;">必须要使用take()方法在获取的时候阻塞</span>
System.<span style="color:#0000ff;">out</span>.println(name+<span style="color:#800000;">"</span><span style="color:#800000;">消费: </span><span style="color:#800000;">"</span> +<span style="color:#000000;"> concurrentLinkedQueue.take());
</span><span style="color:#008000;">//</span><span style="color:#008000;">使用poll()方法 将产生非阻塞效果
</span><span style="color:#008000;">//</span><span style="color:#008000;">System.out.println(name+"消费: " + concurrentLinkedQueue.poll());
</span><span style="color:#008000;">//</span><span style="color:#008000;">还有一个超时的用法,队列空时,指定阻塞时间后返回,不会一直阻塞
</span><span style="color:#008000;">//</span><span style="color:#008000;">但有一个疑问,既然可以不阻塞,为啥还叫阻塞队列?
</span><span style="color:#008000;">//</span><span style="color:#008000;">System.out.println(name+" Consumer " + concurrentLinkedQueue.poll(300, TimeUnit.MILLISECONDS)); </span>
} <span style="color:#0000ff;">catch</span><span style="color:#000000;"> (Exception e) {
</span><span style="color:#008000;">//</span><span style="color:#008000;"> TODO Auto-generated catch block</span>
e.printStackTrace();
}
}
}
}
}
非阻塞队列
基于链接节点的、无界的、线程安全。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列检索操作从队列头部获得元素。当许多线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许 null 元素。
例子
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
public class NoBlockQueue {
private static ConcurrentLinkedQueue<Integer> concurrentLinkedQueue = new ConcurrentLinkedQueue<Integer>();
</span><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span><span style="color:#000000;"> main(String[] args) {
ExecutorService executorService </span>= Executors.newFixedThreadPool(<span style="color:#800080;">2</span><span style="color:#000000;">);
executorService.submit(</span><span style="color:#0000ff;">new</span> Producer(<span style="color:#800000;">"</span><span style="color:#800000;">producer1</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Producer(<span style="color:#800000;">"</span><span style="color:#800000;">producer2</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Producer(<span style="color:#800000;">"</span><span style="color:#800000;">producer3</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Consumer(<span style="color:#800000;">"</span><span style="color:#800000;">consumer1</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Consumer(<span style="color:#800000;">"</span><span style="color:#800000;">consumer2</span><span style="color:#800000;">"</span><span style="color:#000000;">));
executorService.submit(</span><span style="color:#0000ff;">new</span> Consumer(<span style="color:#800000;">"</span><span style="color:#800000;">consumer3</span><span style="color:#800000;">"</span><span style="color:#000000;">));
}
</span><span style="color:#0000ff;">static</span> <span style="color:#0000ff;">class</span><span style="color:#000000;"> Producer implements Runnable {
</span><span style="color:#0000ff;">private</span><span style="color:#000000;"> String name;
</span><span style="color:#0000ff;">public</span><span style="color:#000000;"> Producer(String name) {
</span><span style="color:#0000ff;">this</span>.name =<span style="color:#000000;"> name;
}
</span><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span><span style="color:#000000;"> run() {
</span><span style="color:#0000ff;">for</span> (<span style="color:#0000ff;">int</span> i = <span style="color:#800080;">1</span>; i < <span style="color:#800080;">10</span>; ++<span style="color:#000000;">i) {
System.</span><span style="color:#0000ff;">out</span>.println(name+ <span style="color:#800000;">"</span><span style="color:#800000;"> start producer </span><span style="color:#800000;">"</span> +<span style="color:#000000;"> i);
concurrentLinkedQueue.add(i);
</span><span style="color:#0000ff;">try</span><span style="color:#000000;"> {
Thread.sleep(</span><span style="color:#800080;">20</span><span style="color:#000000;">);
} </span><span style="color:#0000ff;">catch</span><span style="color:#000000;"> (InterruptedException e) {
</span><span style="color:#008000;">//</span><span style="color:#008000;"> TODO Auto-generated catch block</span>
e.printStackTrace();
}
//System.out.println(name+"end producer " + i);
}
}
}
</span><span style="color:#0000ff;">static</span> <span style="color:#0000ff;">class</span><span style="color:#000000;"> Consumer implements Runnable {
</span><span style="color:#0000ff;">private</span><span style="color:#000000;"> String name;
</span><span style="color:#0000ff;">public</span><span style="color:#000000;"> Consumer(String name) {
</span><span style="color:#0000ff;">this</span>.name =<span style="color:#000000;"> name;
}
</span><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span><span style="color:#000000;"> run() {
</span><span style="color:#0000ff;">for</span> (<span style="color:#0000ff;">int</span> i = <span style="color:#800080;">1</span>; i < <span style="color:#800080;">10</span>; ++<span style="color:#000000;">i) {
</span><span style="color:#0000ff;">try</span><span style="color:#000000;"> {
System.</span><span style="color:#0000ff;">out</span>.println(name+<span style="color:#800000;">"</span><span style="color:#800000;"> Consumer </span><span style="color:#800000;">"</span> +<span style="color:#000000;"> concurrentLinkedQueue.poll());
} </span><span style="color:#0000ff;">catch</span><span style="color:#000000;"> (Exception e) {
</span><span style="color:#008000;">//</span><span style="color:#008000;"> TODO Auto-generated catch block</span>
e.printStackTrace();
}
// System.out.println();
// System.out.println(name+" end Consumer " + i);
}
}
}
}
在并发编程中,一般推荐使用阻塞队列,这样实现可以尽量地避免程序出现意外的错误。阻塞队列使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。还有其他类似的场景,只要符合生产者-消费者模型的都可以使用阻塞队列。
使用非阻塞队列,虽然能即时返回结果(消费结果),但必须自行编码解决返回为空的情况处理(以及消费重试等问题)。
另外他们都是线程安全的,不用考虑线程同步问题。