目录
Java集合概览
java集合也叫做容器,主要由两大接口派生而来:一个是Collection接口,主要用于存放单一元素,另一个是Map接口,主要存放键值对。对于Collection接口,下面又有三个主要的子接口:List、Set、Queue。
List,Set,Queue,Map四者的区别?
- List: 存储的元素是有序的,可重复的。
- Set: 存储的元素不可重复,无序。
- Queue: 有序,可重复,先进先出。
- Map: 使用键值对(key-value)存储,key是无序的、不可重复的,value是无需的、可重复的,每个键最多映射到一个值。
注意:有序、无序指的是是否按存放顺序存储。
List 接口
List 接口表示有序的集合,允许重复的元素,并可以通过索引访问元素。
主要实现类:
- ArrayList:基于动态数组的实现,适合随机访问。
- LinkedList:基于双向链表的实现,适合频繁的插入和删除操作。
- Vector:实现了与 ArrayList 类似,但它是同步的,适合多线程环境。
- Stack:继承自 Vector,实现了后进先出的栈数据结构。
ArrayList 和 LinkedList,默认情况下不是线程安全的。如果你需要一个线程安全且高效的 List 实现,有几种选择:
- 使用 Collections.synchronizedList
这是最简单的方法,通过包装现有的 List 实现类来提供同步支持。
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
这个方法为所有的访问方法添加了同步锁,这是线程安全的,但在高并发环境下性能可能不是最优的,因为每次访问都需要获取锁。
- 使用 CopyOnWriteArrayList
CopyOnWriteArrayList 是 java.util.concurrent 包提供的线程安全的 List 实现,非常适合读多写少的场景。
List<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
CopyOnWriteArrayList 的特点是:
读操作不加锁:读操作不会阻塞,因为是操作的快照副本。
写操作代价高:每次写操作(添加、修改、删除)会创建整个列表的一个新副本,适合读多写少的场景。
- 使用 ConcurrentLinkedQueue
虽然 ConcurrentLinkedQueue 不是 List 实现,但它提供了一个高效的、线程安全的队列,如果你需要先进先出的语义,可以考虑这个选项。
Queue<String> concurrentLinkedQueue = new ConcurrentLinkedQueue<>();
- 使用 Vector
Vector 是线程安全的 List 实现类,每个方法都进行了同步处理,但它相对较老且性能一般,通常不推荐在新项目中使用。
List<String> vector = new Vector<>();
总结
高并发读多写少:选择 CopyOnWriteArrayList。
简单同步:使用 Collections.synchronizedList 包装 ArrayList 或 LinkedList。
FIFO 队列:考虑 ConcurrentLinkedQueue 作为替代。
传统方法:Vector 是线程安全的,但性能较低,建议仅用于维护旧代码。
根据你的具体需求和场景选择适合的 List 实现,可以确保在多线程环境下既满足线程安全要求,又能提供良好的性能。
set接口
Set 接口表示无序的集合,不允许重复元素。
主要实现类:
HashSet:基于哈希表的实现,提供快速的查找和插入操作。
LinkedHashSet:继承自 HashSet 并保留插入顺序。
TreeSet:基于红黑树的实现,元素自动排序。
Set 实现(如 HashSet、TreeSet、LinkedHashSet)都不是线程安全的。如果你需要一个线程安全且高效的 Set 实现,可以考虑以下选项:
- 使用 Collections.synchronizedSet
这是最简单的方法,通过包装现有的 Set 实现类来提供同步支持。
Set<String> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
这个方法为所有的访问方法添加了同步锁,虽然是线程安全的,但在高并发环境下性能可能不是最优的,因为每次访问都需要获取锁。
- 使用 ConcurrentSkipListSet
ConcurrentSkipListSet 是 java.util.concurrent 包提供的线程安全的 Set 实现,基于 ConcurrentSkipListMap。
Set<String> concurrentSkipListSet = new ConcurrentSkipListSet<>();
ConcurrentSkipListSet 的特点是:
线程安全:通过细粒度的锁和无锁操作实现高效并发。
自然排序:基于跳跃表,元素按自然顺序排序(或者按提供的比较器排序)。
它是一种基于层级结构的链表,元素按顺序存储,同时具有多层链表辅助实现快速访问。
- 跳跃表的基本原理
- 层级结构:跳跃表由多个层构成。底层(Level 0)是一个单链表,包含所有元素。每一层向上,元素数量减少,形成一个塔形结构。每层的节点指向下层链表的一些节点。
- 快速访问:通过多层索引,跳跃表实现了从高层跳跃到低层的功能,大幅加快了插入、删除和查找操作的速度。
- 概率性平衡:跳跃表自动平衡自己,通过随机机制决定每个元素所在的层,通常每层的数量是下面一层的一半。
- 使用 CopyOnWriteArraySet
CopyOnWriteArraySet 是实现了 Set 接口的线程安全集合类,内部是基于 CopyOnWriteArrayList 实现的。特别适合读操作远多于写操作的场景。
Set<String> copyOnWriteArraySet = new CopyOnWriteArraySet<>();
CopyOnWriteArraySet 的特点是:
读操作不加锁:读操作不会阻塞,因为是操作的快照副本。
写操作代价高:每次写操作(添加、删除)都会创建整个集合的一个新副本,适合读多写少的场景。
4. 使用 ConcurrentHashMap 的 KeySet
自 Java 8 以来,ConcurrentHashMap 提供了一种高效的并发 Set 实现,通过 ConcurrentHashMap.keySet(defaultValue)
Set<String> concurrentHashSet = ConcurrentHashMap.newKeySet();
这是一个高效的线程安全 Set,并且继承了 ConcurrentHashMap 的并发性能优势。
总结
简单同步:使用 Collections.synchronizedSet 包装 HashSet 或其他 Set 实现。
高并发读多写少:选择 CopyOnWriteArraySet。
自然排序、高并发:选择 ConcurrentSkipListSet。
高并发且无序:选择基于 ConcurrentHashMap 的 newKeySet() 方法。
通过以上几个实现,你可以根据并发需求和性能考虑选择最合适的线程安全 Set 实现。
Queue接口
Queue 接口表示一个先进先出的队列,用于按顺序处理元素。
主要实现类:
- LinkedList:既实现了 List 接口,也实现了 Queue 接口,适合实现双端队列。
- PriorityQueue:基于堆排序的实现,元素按自然顺序或指定的比较器排序。
- ArrayDeque:实现了双端队列(Deque)接口,提供了比 LinkedList 更高效的队列操作。
如果你需要一个线程安全且高效的 Queue 实现,Java 的并发包 java.util.concurrent 提供了一些强大的工具。选择合适的实现取决于具体的使用场景,例如是否需要阻塞队列,是否对元素的有序性有要求等。
线程安全的 Queue 实现
-
ConcurrentLinkedQueue
ConcurrentLinkedQueue 是一个基于无锁算法的高效非阻塞队列实现,适用于高并发环境中的生产者-消费者场景。 -
BlockingQueue 家族
-
ArrayBlockingQueue
ArrayBlockingQueue 是一个基于数组的阻塞队列,固定容量。队列满时插入操作将阻塞,队列空时移除操作将阻塞。 -
LinkedBlockingQueue
LinkedBlockingQueue 是一个基于链表的阻塞队列,可指定容量限制。如果未指定容量,默认大小是 Integer.MAX_VALUE。 -
PriorityBlockingQueue
PriorityBlockingQueue 是一个带优先级的阻塞队列,使用自然排序或提供的比较器对元素进行排序。 -
DelayQueue
DelayQueue 是一个延迟队列,队列中的元素只能在指定的延迟时间之后才能被消费。通常用于定时任务调度。 -
SynchronousQueue
SynchronousQueue 是一个不存储元素的队列,每一个 put 操作必须等待一个 take 操作,反之亦然。
- TransferQueue
- LinkedTransferQueue
LinkedTransferQueue 是 TransferQueue 接口的实现,支持元素的传递。如果消费者已经等待,生产者可以将元素直接传递给消费者。
总结
根据不同使用场景和需求,你可以选择合适的线程安全且高效的 Queue 实现:
高并发、非阻塞队列:使用 ConcurrentLinkedQueue。
需要阻塞行为:使用 BlockingQueue 相关实现,如 ArrayBlockingQueue、LinkedBlockingQueue。
需要优先级:使用 PriorityBlockingQueue。
需要延迟队列:使用 DelayQueue。
点对点通信:使用 SynchronousQueue。
自由传递(生产者可直接传递给消费者):使用 LinkedTransferQueue。
通过这些高级队列实现,Java 提供了丰富的工具来处理各种多线程场景,确保高效和线程安全。
Map 接口
Map 接口表示键值对的集合,键唯一,值可以重复。
主要实现类:
- HashMap:基于哈希表的实现,提供快速的查找和插入操作。
- LinkedHashMap:继承自 HashMap 并保留插入顺序。
- TreeMap:基于红黑树的实现,键自动排序。
- Hashtable:与 HashMap 类似,但它是同步的,适合多线程环境。
- ConcurrentHashMap:设计用于并发场景,提供了高效的并发操作支持。
Map 接口的默认实现类(如 HashMap, TreeMap 等)并不是线程安全的。所以在多线程环境中使用的时候,需要考虑线程安全且高效的实现。Java 提供了一些线程安全的 Map 实现,主要在 java.util.concurrent 包中。
- ConcurrentHashMap
ConcurrentHashMap 是最常用的线程安全高效 Map 实现。它通过细粒度的锁机制(如分段锁和CAS操作)实现了高效的并发访问,适用于大多数并发场景。
特点:
高效并发:允许并发读取,写操作使用锁分片,减少锁争用。
无锁读取:大多数读取操作是无锁的,通过CAS原子操作更新值,使读写分离。
默认大小:默认初始容量为 16,扩容时通过双倍扩容机制。
- Collections.synchronizedMap
Collections.synchronizedMap 提供了一种将现有 Map 转换为线程安全实现的简单方法。它对所有方法进行了同步包装,即每个访问方法都通过对相应同步块加锁来实现线程安全。
特点:
简单易用:能快速将任何 Map 实现转换为线程安全的实现。
全局锁:使用的是单独的全局锁,在高并发情况下性能不佳。
- ConcurrentSkipListMap
ConcurrentSkipListMap 是一个基于跳跃表(Skip List)数据结构的线程安全 Map 实现,元素按照键的自然顺序或指定的比较器顺序存储。
特点:
有序性:提供键的自然排序或指定的排序器排序,适合需要顺序访问的场景。
高效并发:支持高效的并发读写操作,使用无锁操作和细粒度锁。
适合应用:适用于需要顺序访问和高并发操作的应用,如缓存、限流控制等。
总结
根据不同的使用场景和需求,你可以选择以下线程安全且高效的 Map 实现:
- 高并发和无序存储:选择 ConcurrentHashMap。
- 快速转换现有 Map:使用 Collections.synchronizedMap 包装现有 Map 实现。
- 高并发和有序存储:选择 ConcurrentSkipListMap,适用于需要顺序操作的场景。
通过理解和应用这些并发 Map 实现,你可以在多线程环境中高效、安全地使用映射集合,确保数据一致性和操作效率。
其他相关接口和类
除了上述接口和实现类,Java 集合框架还包括一些其他常用的接口和辅助类:
- Deque 接口:表示双端队列,既可以从两端插入和移除元素。
实现类:ArrayDeque 和 LinkedList - SortedSet 接口:继承自 Set 接口,表示有序的集合。
实现类:TreeSet - NavigableSet 接口:继承自 SortedSet 接口,提供了导航方法。
实现类:TreeSet - SortedMap 接口:继承自 Map 接口,表示有序的键值对集合。
实现类:TreeMap - NavigableMap 接口:继承自 SortedMap 接口,提供了导航方法。
实现类:TreeMap
标签:Set,java,实现,List,接口,并发,线程,集合,Java From: https://blog.csdn.net/LSP20020926/article/details/142454595没有了,感谢大家阅读,这篇就是分类一下,可以让人好记忆,系统的认识一下Java集合。以后我会持续更新每个集合框架更深入的理解。