线程不安全的容器

  • HashMap
  • TreeMap
  • LinkedHashMap

Collections.synchronizedXXX

 Collections 类是一个工具类,该方法提供了大量对集合进行操作的方法,比如集合的排序、查找等操作。最重要的是,在它里面提供了几个静态工厂方法来创建同步容器类,如下:

1
2
3
Map map = Collections.synchronizedMap(new HashMap<>());
List list = Collections.synchronizedList(new ArrayList<>());
Set set = Collections.synchronizedSet(new HashSet<>());

 它的实现原理是在 Collections 类中添加==静态内部类==,静态内部类实现相应的接口,并在操作容器的方法中加入 synchronized 关键字

由于方法都是通过添加 sychronized 关键字来实现,因此并发行并不高,并不适合并发量较大的操作

线程安全的 Map

一. HashTable

HashTable 与 普通 Map 的区别是 HashTable 继承了 Dictionary 类,并且 在所有的控制方法上加了 synchronized 关键字

通过添加 synchronized 关键字对方法加锁,因此并不适合并发量较大的操作

二、ConcurrentHashMap

 相比于HashTable直接锁住整张表,ConcurrentHashMap将整张表分成N个段(默认16段),每次操作只锁住一个段,因此效率远高于HashTable

相对于 HashTable 和 sychronizedMap,ConcurrentHashMap 更加适合并发量较高的操作

三、ConcurrentSkipListMap

 相较于ConcurrentHashMap跳表结构,ConcurrentSkipListMap是跳表(skip list)结构。在理论上能够在O(log(n))时间内完成查找、插入、删除操作。与其他的 Map 不同的是,ConcurrentSkipListMap 是按照 key 值的升序进行排列的,是个==有序的 Map 集合==

由于其时间复杂度为O(log(n))

因此在并发量较低的时候,其性能不如 ConcurrentHashMap。

但在并发量较高的情况下,使用 ConcurrentSkipListMap 能够展现出更高的性能。

线程安全的 Queue

 JDK 中提供两种线程安全的队列,一种是高性能队列 ConcurrentLinkedQueue,一种是阻塞队列 BlockingQueue,这两种队列都继承自 Queue

一. ConcurrentLinkedQueue
二. BlockingQueue
  • ArrayBlockingQueue:基于数组的阻塞队列实现,在 ArrayBlockingQueue 内部,维护了一个定长的数组,以便缓存队列中的数据对象,其内部没实现读写分离,也就意味着生产者和消费者不能完全并行,长度是需要定义的。ArrayBlockingQueue 也叫有界队列,在很多场合适用。
  • LinkedBlockingQueue:基于链表的阻塞队列,同 ArrayBlockingQueue 类似,其内部也维持着一个数据缓冲队列(该队列由一个链表构成),LinkedBlockingQueue 之所以能够高效的处理并发数据,是因为其内部实现采用分离锁(读写分离两个锁),从而实现生产者和消费者操作的完全并行运行。是一个无界队列。
  • PriorityBlockingQueue:基于优先级的阻塞队列(优先级的判断通过构造函数传入的 Compator 对象来决定,也就是说传入队列的对象需要实现 Comparable 接口),在实现 PriorityBlockingQueue 时,内部控制线程同步的锁采用的是公平锁,它是一个无界队列。
  • DelayQueue:带有延迟时间的 Queue,其中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue 中的元素必须实现 Delayed 接口,DelayQueue 是一个没有大小限制的队列,应用场景很多,比如对缓存超时的数据进行移除、任务超时处理、空闲连接的关闭等。
  • SynchronousQueue:一种没有缓冲的队列,生产者生产的数据直接会被消费者获取并消费。

线程安全的 List