【JavaEE】线程安全的集合类

目录

前言

多线程环境使用ArrayList

多线程环境使用队列

多线程环境下使用哈希表

1.HashTable

2.ConcurrentHashMap

面试题

1.ConcurrentHashMap的读会否需要加锁,为什么?

2.介绍下ConcurrentHashMap的锁分段技术?

3.ConcurrentHashMap在jdk1.8做了哪些优化?

4.HashTable和HashMap、ConcurrentHashMap之间的区别?


前言

在前面我们学习了一些在中java集合类,例如ArrayList、Queue、HashMap、StringBuilder等一些常见的集合类,但这些都是线程不安全的类,不能在多线程中使用。考虑多线程的情况下,我需要使用一些线程安全的类,Vector、Stack、HashTable是线程安全的类,但并不建议使用。

在多线程的情况下,建议自己加锁,或者使用一些带锁的数据结构

多线程环境使用ArrayList

ArrayList本身是一个线程不安全的集合类,在多线程的情况下,对于其读和写操作,存在着线程安全问题,因此,提出了下面几种解决方法:

  1. 自己使用同步机制(synchronized或者ReentrantLock)
  2. Collection.synchronizedList(new ArrayList);其实就是在相关方法面前进行synchronized的加锁。

synchronizedList 是标准库提供的⼀个基于synchronized进⾏线程同步的List.synchronizedList 的关键操作上都带有synchronized

  3.CopyOnWriteArrayList:即写时复刻的容器

在进行读操作时,容器不用做任何改变。当我们往容器里添加元素的时候,不会直接往当前容器里添加,而是会先对当前容器Copy复制出一个新的容器,往后往新的容器里添加元素。当添加完元素之后,再将原容器的引用指向新的容器。

我们可以查看CopyOnWriteArrayList中的add方法,我们可以看到和我们上面说的一致。

当我们想要进行写操作,会先进行拷贝,再在拷贝的数组里存放数据。

CopyOnWriteArrayList容器的优缺点

优点

  1. 读操作无需加锁:由于使用了写时拷贝策略,在读取操作的时候,可以在没有锁的情况下进行,提高了读取操作的性能。在读多写少的场景下,不需要加锁竞争。
Java 中,常见的线程安全的 `List` 集合类型有以下几种: ### Vector `Vector` 是一个基于动态数组实现的线程安全的 `List` 集合。它的大多数方法都使用 `synchronized` 关键字进行同步,以此来保证线程安全。不过,由于同步带来的开销,其性能通常不如 `ArrayList`。示例代码如下: ```java import java.util.Vector; public class VectorExample { public static void main(String[] args) { Vector<String> vector = new Vector<>(); vector.add("apple"); vector.add("banana"); System.out.println(vector.get(0)); } } ``` 但需注意,虽然 `Vector` 是线程安全的,但由于其在一些关键方法上都加了 `synchronized`,导致同时读以及单线程中也要加锁,Java 官方已将其标为不建议使用的类[^1][^2]。 ### CopyOnWriteArrayList `CopyOnWriteArrayList` 是 Java 并发包(`java.util.concurrent`)中的一个线程安全的 `List` 集合。它采用写时复制(Copy-On-Write)的策略,在进行写操作(如 `add`、`set`、`remove` 等)时,会先将原数组进行复制,然后在新数组上进行修改,最后将新数组赋值给原数组的引用。读操作则直接在原数组上进行,不需要加锁。这种方式保证了读操作的高效性,但写操作的开销相对较大,因为需要复制数组。示例代码如下: ```java import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class CopyOnWriteArrayListExample { public static void main(String[] args) { List<String> list = new CopyOnWriteArrayList<>(); list.add("apple"); list.add("banana"); System.out.println(list.get(0)); } } ``` ### 使用 Collections.synchronizedList 包装的 List `Collections.synchronizedList` 方法可以将一个普通的 `List` 转换为线程安全的 `List`。它通过在每个方法上添加同步锁来保证线程安全。示例代码如下: ```java import java.util.ArrayList; import java.util.Collections; import java.util.List; public class SynchronizedListExample { public static void main(String[] args) { List<String> list = new ArrayList<>(); List<String> synchronizedList = Collections.synchronizedList(list); synchronizedList.add("apple"); synchronizedList.add("banana"); System.out.println(synchronizedList.get(0)); } } ```
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小猪同学hy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值