并发类容器(二)


一、非阻塞队列ConcurrentLinkedQueue

         高性能无阻塞无界队列:ConcurrentLinkedQueue,是一个适用于高并发场景下的队列,通过无锁的方式,实现了高并发状态下的高性能,通常ConcurrentLinkedQueue性能好于BlockingQueue。它是一个基于连接节点的无界线程安全队列。该队列的元素遵循先进先出的原则.头是最先加入的,尾是最近加入的,该队列不允许null元素。

public class UseConcurrentLinkedQueue {

public static void main(String[] args) {
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
queue.add("aaa"); //在该队列的尾部插入指定的元素,底层调用的offer
queue.offer("bbb"); //会校验null值
queue.offer("ccc");
//此时队列中元素为 ccc bbb aaa
System.out.println("poll : " + queue.poll());//检索并删除此队列的头部,如果此队列为空,则返回 null 。
//此时队列中元素为 ccc bbb
System.out.println("peek :" +queue.peek());//检索但不删除此队列的头,如果此队列为空,则返回 null 。
//此时队列中元素为 ccc bbb
System.out.println("==============forEach================");
queue.forEach(System.out :: println);
}
}


二、阻塞队列

    1、ArrayBlockingQueue

        基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,其内部没有实现读写分离,也就意味着生产者和消费者不能完全并行,长度是需要定义的。(它是一个有界队列)

public class UseArrayBlockingQueue {

public static void main(String[] args) throws Exception{
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.add("aaa") ); //插入元素到队列尾部,成功true ,队列满了IllegalStateException
System.out.println( queue.offer("bbb" ));//成功true,失败false
queue.put("ccc"); //如果满了,等待
System.out.println(queue.offer("ddd",3, TimeUnit.SECONDS));//如果满了,指定等待时间再插入

System.out.println("peek : " + queue.peek()); //不移除
System.out.println("poll : " + queue.poll()); //移除
//System.out.println("poll : " + queue.poll());
//System.out.println("poll : " + queue.poll());
System.out.println("peek 3s : " + queue.poll(3,TimeUnit.SECONDS)); //如果空了,等待指定时间在获取
System.out.println("take : " + queue.take()); //如果空了,等待

ArrayList<String> list = new ArrayList<>();
System.out.println("drainTo : " + queue.drainTo(list, 2)); //将队列中的元素移除到list

System.out.println("list size : " + list.size());
System.out.println("queue size : " + queue.size());

}
}

    2、LinkedBlockingQueue

        LinkedBlockingQueue阻塞队列大小的配置是可选的,如果我们初始化时指定一个大小,它就是有边界的,如果不指定,它就是无边界的。说是无边界,其实是采用了默认大小为Integer.MAX_VALUE的容量 。它的内部实现是一个链表。Api和用法与ArrayBlockingQueue一样。

    3、SynchronousQueue

        一种没有缓冲的队列,当一个线程插入一个元素后会被阻塞,除非这个元素被另一个线程消费。

public class UseSynchronousQueue {

public static void main(String[] args) throws Exception{
SynchronousQueue<String> queue = new SynchronousQueue<>();
//queue.add("aaa"); //直接添加会报 Queue full,说明没有容量

new Thread(() -> {
try {
System.out.println("take : " + queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();

new Thread(() -> {
System.out.println("offer : " + queue.offer("aaa"));
}).start();

TimeUnit.SECONDS.sleep(2);

}
}

    4、PriorityBlockingQueue

        基于优先级的阻塞队列(优先级的判断通过构造函数传入的Compator对象来决定,也就是说传入队列的对象必须实现Comparable接口)。该队列是无界队列,不可以存null。

public class UsePriorityBlockingQueue {

public static void main(String[] args) throws Exception{
PriorityBlockingQueue queue = new PriorityBlockingQueue();

queue.add(new Task(4,"ddd"));
queue.add(new Task(3,"ccc"));
queue.add(new Task(1,"aaa"));
queue.add(new Task(2,"bbb"));

//每次取出根据优先级来
System.out.println("queue : " + queue);
System.out.println("take : " + queue.take());
System.out.println("queue : " + queue);
System.out.println("take : " + queue.take());
System.out.println("queue : " + queue);
System.out.println("take : " + queue.take());
System.out.println("queue : " + queue);

}

}

class Task implements Comparable<Task> {

private Integer id;
private String name;

public Task(Integer id, String name) {
this.id = id;
this.name = name;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "Task{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}

@Override
public int compareTo(Task task) {
return this.id > task.id ? 1 : (this.id < task.id ? -1 : 0);
}
}

    5、LinkedBlockingDeque

    双端队列,可以从头部和尾部进行插入和提取

public class UseLinkedBlockingDeque {

public static void main(String[] args) throws Exception{
LinkedBlockingDeque<String> deque = new LinkedBlockingDeque<>();
deque.addFirst("a");
deque.offerFirst("b");
deque.putFirst("c");

deque.addLast("d");
deque.offerLast("e");
deque.putLast("f");

System.out.println("deque : " + deque);
System.out.println("takeFirst : " + deque.takeFirst()); //头部移除
System.out.println("peekLast : " + deque.peekLast()); //获取尾部,不移除
System.out.println("deque : " + deque);
}
}

    6、DelayQueue

        带有延迟时间的queue,其中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue中的元素必须实现Delayed接口,DelayQueue是一个没有大小限制的队列,不允许有null。

import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class UseDelayQueue {

public static void main(String[] args) throws Exception{
System.out.println("网吧开始营业咯...");
WangBa wangBa = new WangBa();
Thread thread = new Thread(wangBa);
thread.start();

//小学生上机
wangBa.shangji("002","李四",5);
wangBa.shangji("001","张三",1);
wangBa.shangji("003","王五",10);

System.out.println("=========================");


}
}

/**
* 网吧
*/
class WangBa implements Runnable{

private DelayQueue<XiaoXueSheng> queue = new DelayQueue<>();

private boolean yingye = true;

public void shangji(String id, String name, int money) {
XiaoXueSheng xiaoXueSheng = new XiaoXueSheng(id, name, 1000 * money + System.currentTimeMillis());
System.out.println( " 身份证" + xiaoXueSheng.getId()+ "网名" + xiaoXueSheng.getName() + "交钱" + money + "块,开始上机...");
this.queue.add(xiaoXueSheng);
}

public void xiaji(XiaoXueSheng xiaoXueSheng) {
System.out.println(" 身份证" + xiaoXueSheng.getId()+ "网名" + xiaoXueSheng.getName() + "时间到下机...");
}


@Override
public void run() {
while (yingye) {
try {
XiaoXueSheng xiaoXueSheng = queue.take();
xiaji(xiaoXueSheng);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

/**
* 小学生
*/
class XiaoXueSheng implements Delayed {

private String id;

private String name;
//结束时间
private long endTime;

public XiaoXueSheng(String id, String name, long endTime) {
this.id = id;
this.name = name;
this.endTime = endTime;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public long getEndTime() {
return endTime;
}

public void setEndTime(long endTime) {
this.endTime = endTime;
}


/**
* 用来判断是否到了截止时间
*/
@Override
public long getDelay(TimeUnit unit) {
return endTime - System.currentTimeMillis();
}
/**
* 相互比较排序用
*/
@Override
public int compareTo(Delayed delayed) {
XiaoXueSheng xiaoXueSheng = (XiaoXueSheng)delayed;
long ret = this.getDelay(TimeUnit.SECONDS) - xiaoXueSheng.getDelay(TimeUnit.SECONDS);
return ret > 0 ? 1 :(ret < 0 ? -1 : 0);
}
}