什么是跳表
跳表是用于解决链表的查找问题,由于性能上链表比数组新增元素要快,查询比数组要慢,所以因此引入了跳表技术。跳表的实现上,是通过概率性在table上面添加索引,通过索引的方式查询上,解决了速度慢的问题,由于使用了索引,该跳表在数据上是属于有序的列表。
ConcurrentSkipListMap、ConcurrentSkipListSet是有序的列表,它是(CAS)保证了在多线程环境下线程安全的问题,ConcurrentSkipListSet内部使用的就是ConcurrentSkipListMap,在此基础上进行了包装而已。
TreeMap 、TreeSet是有序的列表,它只适合单线程环境下使用,不能保证线程安全的问题,TreeSet内部使用的就是TreeMap,同样也是在此基础上进行包装。
写时复制容器
写时复制容器一般用于读多,写少的情况,实现上是通过对原数组进行copy一份,然后再新数组里面进行操作,如果此时有读操作,实际上还是读取的原数组,只有当新数组处理完毕之后,才会把新数组替换掉原数组。注意:此时的可见性并不是弱一致,因为读写操作的不是同一个table,所以没有一致性。
CopyOnWriteArrayList 和 CopyOnWriteArraySet 两个写时复制容器,其中CopyOnWriteArraySet内部采用CopyOnWriteArrayList的实现,除了equals方法之外,其他的大部分都是调用了CopyOnWriteArrayList内部的方法。
阻塞队列
BlockingQueue:队列为空的时候,取时阻塞;队列满了的时候,写时阻塞。实现阻塞,在blockingQueue中关键的方法为put、take。
其实现有:
- ArrayBlockingQueue:一个由数组组成的有界阻塞队列,使用同一把锁;
- LinkedBlockingQueue:一个由链表组成的有界阻塞队列,读写分离锁+Condition;
- PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列,内部采用ReentrantLock以及condition实现锁,同时使用的也是PriorityQueue;
- DelayQueue:一个使用优先级队列实现的无界阻塞队列,适用于对时间相关的操作,当业务数据到期后,会从此中进行take到并置为无效,内部采用的可重入锁ReentrantLock,以及PriorityQueue;
- SynchronousQueue:一个不存储元素的阻塞队列,即每次put后需要take才能继续put,采用的可重入锁(ReentrantLock),有公平和非公平两种形式;
- LinkedTransferQueue:一个由链表结构组成的无界阻塞队列,添加元素的时候,会尝试去判断当前是否有take的线程,如果有,那么直接交出去,而不进行入队,使用的locksupport;
- LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列,即可以从头/尾进行插入/取出,使用的可重入锁(ReentrantLock)以及condition通知其不为空和不满,使用了工作密取;
- 个人理解:BlockingQueue是基于AQS实现的阻塞队列,BlockingQueue内部存在一个queue数组,用于存放提交的数据,在多线程调度下进行数据传递。从而实现根据数据queue数组进行线程的阻塞。
例子:使用blockingQueue实现一个阻塞队列
使用到了以下几个类:testQueue(测试类)、readQueue(读取元素类)、writeQueue(写入元素类)、smallQueue(实现blockingQueue类)、Order(业务类)
- testQueue类代码:
package queue;
//类说明:启动方法类,用于启动读写线程
public class testQueue{
//设置队列容量为5个
private final smallQueue<Order> smallQueue = new smallQueue<Order>(5);
public static void main(String[] args) {
testQueue testQueue = new testQueue();
for(int i=0;i<20;i++){
//创建20个读线程
new Thread(new readQueue(testQueue.smallQueue)).start();
}
//创建一个写线程
new Thread(new writeQueue(testQueue.smallQueue)).start();
}
}
- readQueue类代码:
package queue;
import java.util.concurrent.TimeUnit;
import testDemo.Order;
public class readQueue implements Runnable{
private final smallQueue<Order> smallQueue;
public readQueue(smallQueue<Order> smallQueue){
this.smallQueue = smallQueue;