
面试题一:List和Queue的区别?
Queue添加了这些对线程友好的API,offer(),peek(),poll();BlockQueue额外添加了put(),take()api,实现阻塞
1.容器分成两类Collection和Map
2.Queue专门为高并发做准备的
一、HashMap,HashTable,CurrentHashmap
HashMap,是线程不安全的
HashTable,线程安全的,使用synchronized锁,效率低
CurrentHashMap,线程安全的,推荐使用
HashTable,Collections.sychronizedMap,CurrentHashMap插入、查询效率比较
插入效率:CurrentHashMap最慢,因为涉及链表和红黑树
查询效率:CurrentHashMap最快
二、ArrayList,Vector,CurrentLinkQueue
ArrayList,是线程不安全的
Vector,是线程安全,使用synchronized锁,效率低
CurrentLinkQueue,是线程安全的,推荐使用,使用CAS来加锁
多线程程序,在使用容器时,推荐使用Queue
Queue<String> queue = new ConcurrentLinkedQueue<>();
queue.poll();
ConcurrentLinkedQueue源码
boolean casItem(E cmp, E val) {
return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);//可以看出使用CAS锁
}
三、常用高并发容器
1.ConcurrentHashMap
2.ConcurrentSkipListMap //高并发并且排序,代替treeMap
调表:把一些关键元素抽取到另外一行,查找时从上往下查找

3.CopyOnWriteArrayList 读的量大,写的量小 (写加锁,读不用加锁)
源码:CopyOnWriteArrayList.java
写操作
1.加锁
2.copy一个新的数组
3.把值写入新的数据
4.把新的数据赋值到原来的引用上
读操作
1.不用加锁,直接读取(因为新的部分,与老的内容一摸一样)
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
public E get(int index) {
return get(getArray(), index);
}
4.Queue
常用方法
add();// 加不进去,会抛异常
offer()//通过返回值,判断是否加进去
poll();//获取值,并且remove
peek()//获取值,但是不会remove
5.BlockQueue
put();//如果满了,则这个线程会阻塞
take();//如果拿完了,则这个线程阻塞
6.LinkedBlockingQueue 无界的阻塞队列
源码: LinkedBlockingQueue.java
1.put会阻塞,是通过notFull.await()实现的阻塞
2.condition.await()底层是通过 LockSupport.park来实现的阻塞
public void put(E e) throws InterruptedException {
putLast(e);
}
public void putLast(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
while (!linkLast(node))
notFull.await();
} finally {
lock.unlock();
}
}
7.ArrayBlockingQueue 有界的阻塞队列
8.PriorityQueue 排序队列,内部使用二叉树排序
9.DelayQueue 按照时间上排序的队列;按时间进行任务调度
本质是使用PriorityQueue进去排序的
10.SynchronizedQueue 容量为0的queue,传递任务的队列
这个queue不能存放任何数据,除非前面有一个人获取,才可以往里面装数据(直接从一个线程把数据拿给另外一个线程,可以理解为这个queue不存在,相当于两个线程交换数据)。JUC中线程调度很多时候就是用的这个SynchronizedQueue
//特殊的transferQueue
BlockingQueue<String> strs = new SynchronousQueue<>();
strs.take();
strs.put("aa");//阻塞等待消费者消费,内部就是transfer()
11.LinkedTransferQueue
transfer(): 把数据写入后会阻塞,直到这个数据被取走
场景:用户下了订单,这个订单会进入tranferQueue队列,直到这个订单被处理了,我才告诉用户
本文探讨了Java中不同并发容器的特性与使用场景,包括HashMap、HashTable与CurrentHashMap,ArrayList、Vector与CurrentLinkQueue。重点讲解了HashMap与CurrentHashMap在并发环境下的效率差异,以及ArrayList、Vector与CurrentLinkQueue的线程安全性。还介绍了高并发环境下推荐使用的容器,如ConcurrentHashMap、CopyOnWriteArrayList、Queue等,并详细列举了各种Queue的方法及其行为。最后提到了特殊的队列类型,如SynchronizedQueue、LinkedTransferQueue等,它们在任务调度中的作用。

1万+

被折叠的 条评论
为什么被折叠?



