线程安全的集合类

简介: 线程安全的集合类

Java中提供了许多集合类,其中有的是线程安全的,有的是线程不安全的。线程安全的集合类有:

1. Vector:Vector类实现了一个动态数组,与ArrayList相似,但Vector是同步访问的

2. Stack:Stack是Vector的一个子类,实现了一个“后进先出”的栈

3. Hashtable:Hashtable是一个散列表,与HashMap类似

Hashtable在关键方法上加上了synchronized,相当于对this加锁(整张表都加上锁),则Hashtable只有一把锁,即使是修改或读取不同链表上的元素,也会触发锁冲突

通过上图我们可以发现:读取数据时不涉及到线程安全问题,修改两个不同链表上的元素时,也不会涉及线程安全问题,而当修改的是同一链表上的元素时,则可能会涉及到线程安全问题。

因此,针对读取操作,无需加锁,不同链表的操作,也无需加锁,而当针对同一链表操作时,需要加锁,此时,我们可以考虑使用ConcurrentHashMap

4. ConcurrentHashMap:ConcurrentHashMap能够做到读数据不加锁,且在进行写操作时锁的粒度更小,可以允许多个修改操作并发进行,Java 1.7及其之前,ConcurrentHashMap是通过“分段锁”来实现的,即给若干链表分配一把锁,然而这种方法需要引入额外的空间开销,且实现更复杂

因此,从Java 8 开始,就变成了每个链表一把锁了

此时,若不是操作同一个链表的锁,就不会发生锁冲突

然而此种方法是否需要更多的空间?

不会产生更多的空间代价。Java中任意一个对象都可以直接作为锁对象。哈希表中本就需要有数组,数组的元素都是已经存在的(每个链表的头节点),此时,只需使用链表的头节点(数组元素)作为锁对象即可

且ConcurrentHashMap针对扩容也进行了优化。

Hashtable一旦触发扩容,就由该线程完成整个扩容操作,此时可能会涉及到大量的元素拷贝,因此效率会较低,耗时较长

而ConcurrentHashMap则是采用“化整为零”的方法,即当发现需要扩容时,创建一个新的数组,同时搬运几个元素过去,后续每次线程操作ConcurrentHashMap时,都会搬运元素,每次操作搬运一部分元素。在此扩容期间,新旧数组同时存在。当搬运完最后一个元素时,再把旧数组删掉。在此期间内,插入数据只会向新数组中插入,而查找需要同时查询新数组和旧数组

5. synchronizedList:synchronizedList是标准库中提供的一个基于sychronized进行线程同步的list。synchronizedList的关键操作上都带有synchronized

6. CopyOnWriteArrayList:CopyOnWrite即写时拷贝,当读取顺序表时,此时无线程安全问题,而当有线程要修改其中的值时,就会将list复制一份,修改新表中的内容,并修改引用的指向(操作是原子的,无需加锁)

然而因此此种操作需要进行复制,因此修改操作不能太频繁且表也不应太大

除此之外,也可以根据需求,使用synchronized或ReentrantLock自己实现线程安全的ArrayList

7. BlockingQueue(阻塞队列)

ArrayBlockingQueue:基于数组实现的阻塞队列

LinkedBlockingQueue:基于链表实现的阻塞队列

PriorityBlockingQueue:基于堆实现的带有优先级的阻塞队列

...

虽然以上这些类都是线程安全的,但也不一定能够满足我们多线程操作的需求,因此我们需要根据实际情况选择使用或自己加以实现

目录
相关文章
|
1月前
|
Java 开发者
Java面试题:请解释内存泄漏的原因,并说明如何使用Thread类和ExecutorService实现多线程编程,请解释CountDownLatch和CyclicBarrier在并发编程中的用途和区别
Java面试题:请解释内存泄漏的原因,并说明如何使用Thread类和ExecutorService实现多线程编程,请解释CountDownLatch和CyclicBarrier在并发编程中的用途和区别
26 0
|
7天前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
28 7
|
11天前
|
安全 算法 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(下)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
51 6
|
11天前
|
存储 安全 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(中)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
53 5
|
11天前
|
存储 安全 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(上)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
46 3
|
26天前
|
缓存 安全 Java
多线程线程池问题之为什么手动创建的线程池比使用Executors类提供的线程池更安全
多线程线程池问题之为什么手动创建的线程池比使用Executors类提供的线程池更安全
|
1月前
|
设计模式 存储 安全
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
35 1
|
1月前
|
设计模式 缓存 安全
Java面试题:工厂模式与内存泄漏防范?线程安全与volatile关键字的适用性?并发集合与线程池管理问题
Java面试题:工厂模式与内存泄漏防范?线程安全与volatile关键字的适用性?并发集合与线程池管理问题
39 1
|
1月前
|
设计模式 安全 NoSQL
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
30 0
|
1月前
|
设计模式 存储 缓存
Java面试题:结合单例模式与Java内存模型,设计一个线程安全的单例类?使用内存屏障与Java并发工具类,实现一个高效的并发缓存系统?结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:结合单例模式与Java内存模型,设计一个线程安全的单例类?使用内存屏障与Java并发工具类,实现一个高效的并发缓存系统?结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
20 0