一、基础数据结构
1、大O 表示法
O(1):常数级别,它执行的步数都是恒定的,不会因为输入变大而变大,哈希表的查找就是这个级别。
O(N):线性级别,随着输入变大耗费的步数也正向相关,遍历算法就是这个级别。
O(logN):对数级别,输入每变大一倍,耗费步骤则增加1,二分查找算法属于这个级别。
O(N²):平方级别,随着输入的变大所耗费的步数会成倍增加,一般当你的算法使用双层for循环就是这个级别,比如冒泡排序。
2、数组
每个数组都有一个地址,同时可以通过数组的下标方便的算出每个元素的内存地址,
从而实现快速访问和赋值,所以它通过下标查找的效率是O(1) 级别。
3、链表
链表的元素内存地址是不连续的,通过地址引用的方式指向下个元素。
链表的查询O(N) 这个级别,在头节点(第一个节点)进行插入和删除比较快,只要O(1) 就可以了。
4、队列
先入先出的数据结构,尾插和头出,时间复杂度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 + '\'' +
'}';
}
}