Java多线程_JUC包下的阻塞队列
在前面我们提到了阻塞队列,也用过了LinkedBolckingQueue队列了,在这里,我们主要对 ArrayBlockingQueue,PriorityBlockingQueue,DelayQueue,SynchronousQueue,LinkedTransferQueue,LinkedBlockingDeque的使用方法和应用场景做一个补充。
- ArrayBlockingQueue:基于数组实现的阻塞队列,先进先出队列,有界队列。在创建时必须制定容量大小。并可以指定公平性与非公平性,默认情况下是非公平的,即不保证等待时间最长的队列最优先能够访问队列。
- LinkedBlockingQueue:基于链表实现的阻塞队列,先进先出队列,有界队列。在创建时如果不指定容量大小,则默认大小为Integer.MAX_VALUE。
- PriorityBlockingQueue:按照元素的优先级对元素进行排序,按照优先级顺序出队。并且该阻塞队列为无界阻塞队列,即容量没有上限(源码中它没有容器满的信号标志)。
- DelayQueue:基于PriorityQueue的延时阻塞队列,无界队列。DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。因为DelayQueue是一个无界队列,所以往队列中插入数据的操作永远不会被阻塞,而只有获取数据的操作才会被阻塞。
- SynchronousQueue:一个不存储元素的阻塞队列。
- LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
- LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
(1) ArrayBlockingQueue示例:
import java.util.concurrent.ArrayBlockingQueue; public class ArrayBolckingQueueDemo { static ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(2); public static void main(String[] args) { ArrayBolckingQueueDemo demo = new ArrayBolckingQueueDemo(); Product p = demo.new Product(); Eat e = demo.new Eat(); Thread t1 = new Thread(e); Thread t2 = new Thread(p); t2.start(); t1.start(); } class Product implements Runnable { @Override public void run() { while (true) { try { queue.put("apple"); System.out.println(Thread.currentThread().getName() + "put queue:" + queue.toString()); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Eat implements Runnable { @Override public void run() { while (true) { try { queue.take(); System.out.println(Thread.currentThread().getName() + "eat queue:" + queue.toString()); Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
结果:
(2)LinkedBlockingQueue示例这里不介绍,大家可以看我前面的博客“Java多线程_阻塞队列”
(3)PriorityBlockingQueue示例:
import java.util.concurrent.PriorityBlockingQueue; public class PriorityBlockingQueueDemo { public static void main(String[] args) { PriorityBlockingQueue<People> queue = new PriorityBlockingQueue<>(); PriorityBlockingQueueDemo demo = new PriorityBlockingQueueDemo(); queue.put(demo.new People("tom", 19)); queue.put(demo.new People("jack", 18)); queue.put(demo.new People("tony", 21)); while (!queue.isEmpty()) { try { System.out.println(queue.take().toString()); } catch (InterruptedException e) { e.printStackTrace(); } } } class People implements Comparable<People> { private String name; private Integer age; public People(String name, Integer age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public int compareTo(People o) { if (this.age > o.age) { return 1; } else { return -1; } } @Override public String toString() { // TODO Auto-generated method stub return "name:" + name + " age:" + age; } } }
结果:
(4)DelayQueue应用场景:
1) 关闭空闲连接。服务器中,有很多客户端的连接,空闲一段时间之后需要关闭。
2) 缓存。缓存中的对象,超过了空闲时间,需要从缓存中移出。
3) 任务超时处理。
import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class DelayQueueDemo { public static void main(String[] args) { DelayQueueDemo demo = new DelayQueueDemo(); DelayQueue<People> queue = new DelayQueue<>(); queue.put(demo.new People("tom", 4000 + System.currentTimeMillis())); queue.put(demo.new People("jack", 1000 + System.currentTimeMillis())); queue.put(demo.new People("tony", 6000 + System.currentTimeMillis())); while (!queue.isEmpty()) { try { System.out.println(queue.take().toString()); } catch (InterruptedException e) { e.printStackTrace(); } } } class People implements Delayed { private String name; private long time;// 截止时间 public People(String name, long time) { super(); this.name = name; this.time = time; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getTime() { return time; } public void setTime(long time) { this.time = time; } @Override public String toString() { return "name:" + name + " time:" + time; } @Override public int compareTo(Delayed o) { People p = (People) o; if (time - p.time > 0) { return 1; } else { return -1; } } @Override public long getDelay(TimeUnit unit) { return time - System.currentTimeMillis(); } } }
结果:
(5)SynchronousQueue示例:
注意点:每个 put 必须等待一个 take,反之亦然。
import java.util.Random; import java.util.concurrent.SynchronousQueue; public class SynchronousQueueDemo { static SynchronousQueue<Integer> queue = new SynchronousQueue<>(); public static void main(String[] args) { SynchronousQueueDemo demo = new SynchronousQueueDemo(); Productor p = demo.new Productor(); Consumer c = demo.new Consumer(); Thread t1 = new Thread(p); Thread t2 = new Thread(c); t1.start(); t2.start(); } class Productor implements Runnable { @Override public void run() { while (true) { int data = new Random().nextInt(1000); System.out.println("put " + data); try { queue.put(data); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Consumer implements Runnable { @Override public void run() { while (true) { try { System.out.println("take " + queue.take()); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
结果:
(6)LinkedBlockingDeque和LinkedTransferQueue
这两个队列都是后期才产生的队列。
LinkedTransferQueue是一个由链表结构组成的无界阻塞队列。他与LinkedBolckingQueue最大的不同就是这个队列是无界的,而LinkedBolckingQueue是有界的,用法大致相同,这里不作介绍。
LinkedBlockingDeque最大的不同就是它是一个双向的基于链表的阻塞队列。该阻塞队列同时支持FIFO和FILO两种操作方式,即可以从队列的头和尾同时操作(插入/删除),用法差别也不大,不作介绍。