一、基础数据结构

Java 提供的队列-LMLPHP

1、大O 表示法

O(1):常数级别,它执行的步数都是恒定的,不会因为输入变大而变大,哈希表的查找就是这个级别。
O(N):线性级别,随着输入变大耗费的步数也正向相关,遍历算法就是这个级别。
O(logN):对数级别,输入每变大一倍,耗费步骤则增加1,二分查找算法属于这个级别。
O(N²):平方级别,随着输入的变大所耗费的步数会成倍增加,一般当你的算法使用双层for循环就是这个级别,比如冒泡排序。

2、数组

每个数组都有一个地址,同时可以通过数组的下标方便的算出每个元素的内存地址,
从而实现快速访问和赋值,所以它通过下标查找的效率是O(1) 级别。

3、链表

链表的元素内存地址是不连续的,通过地址引用的方式指向下个元素。
链表的查询O(N) 这个级别,在头节点(第一个节点)进行插入和删除比较快,只要O(1) 就可以了。

4、队列

Java 提供的队列-LMLPHP

先入先出的数据结构,尾插和头出,时间复杂度O(1)。
有界队列 :能装入的元素有限。
无界队列 :能装入的元素无限,只要内存还有,就能一直装下去。

5、栈

先入后出/后入先出的数据结构,尾插尾出,时间复杂度O(1)。

二、非阻塞队列(Queue) 

出列入列都不阻塞。入列时,元素数量超过队列总数,会抛异常,出列时,队列为空,取空值。

常用方法:

add():新增一个元索,假如队列已满,则抛异常。
offer():新增一个元素,假如队列没满则返回 true,假如队列已满,则返回 false。
element():获取队列头部一个元素,假如队列为空,则抛异常。
peek():获取队列头部一个元素,假如队列为空,则返回 null。
remove():执行删除操作,返回队列头部的元素,假如队列为空,则抛异常。
poll():执行删除操作,返回队列头部的元素,假如队列为空,则返回 null。

1、LinkedList(线程不安全)

实现的 List、Deque 接口,单链表的无界双端队列,允许元素为 null。

2、ConcurrentLinkedQueue(线程安全)

单向链表结构的无界并发队列,由CAS实现线程安全,性能高。

3、ConcurrentLinkedDeque(线程安全)

双向链表结构的无界并发队列,由CAS实现线程安全,可以从两端进行元素的插入和删除操作,性能略低于ConcurrentLinkedQueue。

4、PriorityQueue(线程不安全)

基于数组实现,可自动扩容,按照元素的优先级进行排序,在插入和删除元素时保持有序状态。
PriorityQueue中的元素必须实现Comparable接口或者通过构造函数提供一个Comparator对象,以便进行元素的比较和排序。

三、阻塞队列(BlockingQueue)

入列时,如果元素数量超过队列总数,会进行等待(阻塞)。出列时,如果队列为空,会进行等待(阻塞)。阻塞队列线程安全,在队列基础上加了两个重要的接口put()、 take()。

1、ArrayBlockingQueue

基于数组结构,有界阻塞队列,创建时必须制定大小。可指定公平性与非公平性,默认为非公平。
ReentrantLock、Condition 实现线程安全,阻塞和唤醒。

2、LinkedBlockingQueue

基于链表结构,有界阻塞队列,创建时如果不指大小,默认大小为 Integer.MAX_VALUE。
ReentrantLock、Condition 实现线程安全。
使用了两个锁,一个用于生产者线程的访问,另一个用于消费者线程的访问,在生产者-消费者模型场景中使用广。

3、SynchronousQueue

不存储任何元素,一个线程put()必须等待另一个线程的take();一个线程take()也要等待另一个线程的take(),否则阻塞。插入null元素,会抛出NullPointerException。

4、LinkedTransferQueue

基于链表结构的无界阻塞队列, SynchronousQueue 和 LinkedBlockingQueue 的合体,
它使用了CAS操作来保证并发安全性,内部用了多个节点来实现队列,
每个节点包含一个元素以及指向下一个节点的指针,性能比 LinkedBlockingQueue 更高。插入null元素会抛NullPointerException异常。

5、LinkedBlockingDeque

基于双向链表结构的双向阻塞队列,可设置大小,也可无界,支持队列和栈的操作,不支持null元素。

6、PriorityBlockingQueue

基于二叉树实现的无界限(最大值Integer.MAX_VALUE - 8),可按优先级对元素进行排序,按优先级顺序出队。
1.允许插入null元素,不允许插入不可比较的元素。
2.迭代PriorityBlockingQueue时,顺序是无法保证的。
3.不支持remove(Object)操作,无法快速地找到并删除指定元素。

import java.util.concurrent.PriorityBlockingQueue;

public class Task implements Comparable<Task> {
    private String name;
    private int priority;

    public Task(String name, int priority) {
        this.name = name;
        this.priority = priority;
    }

    public String getName() {
        return name;
    }

    public int getPriority() {
        return priority;
    }

    @Override
    public int compareTo(Task o) {
        return Integer.compare(o.priority, this.priority);
    }
}

public class PriorityBlockingQueueTest {
    public static void main(String[] args) {
        // 创建一个PriorityBlockingQueue对象
        PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<Task>();
        // 添加任务到队列中
        queue.offer(new Task("Task1", 3));
        queue.offer(new Task("Task2", 2));
        queue.offer(new Task("Task3", 1));
        // 取出队列中的任务
        while (!queue.isEmpty()) {
            Task task = queue.poll();
            System.out.println("Execute task " + task.getName() + " with priority " + task.getPriority());
        }
    }
}

7、DelayQueue

延时阻塞队列,内部用 PriorityQueue 来存储元素,元素有过期时间,元素的过期时会被取出。

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

public class DelayQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        DelayQueue<DelayElement> queue = new DelayQueue<>();

        // 添加元素到队列
        queue.add(new DelayElement("A", 3000));
        queue.add(new DelayElement("B", 2000));
        queue.add(new DelayElement("C", 1000));

        // 取出元素
        System.out.println(queue.take());
        System.out.println(queue.take());
        System.out.println(queue.take());
    }
}

class DelayElement implements Delayed {
    private String name;
    private long expireTime;

    public DelayElement(String name, long delayTime) {
        this.name = name;
        this.expireTime = System.currentTimeMillis() + delayTime;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return expireTime - System.currentTimeMillis();
    }

    @Override
    public int compareTo(Delayed o) {
        return Long.compare(this.expireTime, ((DelayElement) o).expireTime);
    }

    @Override
    public String toString() {
        return "DelayElement{" +
                "name='" + name + '\'' +
                '}';
    }
}
07-18 04:25