线程安全的List

对于JDK中的线程安全集合类,个人用的一般是map和队列相关的用的比较多,线程安全的List很少会接触到。开发的时候突然遇到别人问我说有没有线程安全的List…一脸懵逼,所以决定网上找找看有没有相关的结构,别说,还真找到了:

Collections.synchronizedList与CopyOnWriteArrayList

本人之前写的话都是用一个锁来锁定的,今天就来看下这两种结构是不是会比自己用锁会更好。

 

调试代码如下:

public static void main(String[] args) {
    List<String> l1 = new CopyOnWriteArrayList<>();
    l1.add("1");

    List<String> l2 = new ArrayList<>();
    List<String> l3 = Collections.synchronizedList(l2);
    l3.add("a");
}

 

先看Collections.synchronizedList:

其实就是内部给你synchronize加了个锁…没啥好看的,不过感觉可以简化下你的代码,至少这个里面的方法全部都是加了锁的。

而且锁的是一个变量,所以锁的粒度小。

 

再看CopyOnWriteArrayList:

当数组有变化时重新建立一个新的数组

一看这个add()就觉得在性能方面肯定不太靠谱:

第一个原因是使用的是Lock,之前分析ReentrantLock的时候说过,虽然它比synchronize提供了更丰富的功能,但是由于它是API级别的,JVM不会对这个锁进行优化,而synchronize之前分析过,它的锁是一步步升级上来的。

第二个原因是它每增加一个元素都要copy一遍旧数组中的元素,生成一个新数组。

 

好了…接下来的我就不用看了,我觉得一般情况下,前面那个用的会比较多,后面这个的场景我暂时没碰到。

### 线程安全 List 的实现及用法 Java 提供了几种方式来创建线程安全的 `List`,每种方式都有其特定的应用场景和优缺点。 #### 1. 使用 `Collections.synchronizedList` `Collections.synchronizedList` 是一种简单的方式,可以将任意的 `List` 转换成线程安全的形式。它的核心原理是对底层的 `List` 添加同步控制,确保每次访问或修改操作都被序列化执行[^2]。 以下是使用 `Collections.synchronizedList` 的示例代码: ```java import java.util.Collections; import java.util.List; import java.util.ArrayList; public class SynchronizedListExample { public static void main(String[] args) { List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>()); // 同步块确保多线程环境下的安全性 synchronized (synchronizedList) { for (String item : synchronizedList) { System.out.println(item); } } } } ``` 需要注意的是,虽然单个方法调用(如 `add` 和 `remove`)是线程安全的,但如果涉及多个连续的操作,则需要手动加上同步块以保证整体逻辑的安全性[^2]。 --- #### 2. 使用 `Vector` `Vector` 是 Java 中较早的一种线程安全的 `List` 实现。它通过对几乎所有公共方法添加 `synchronized` 关键字来实现线程安全性。然而,这种方式的性能较差,因为每一次操作都需要获取锁[^3]。 以下是一个简单的例子: ```java import java.util.Vector; public class VectorExample { public static void main(String[] args) { Vector<String> vector = new Vector<>(); vector.add("Element"); String element = vector.get(0); System.out.println(element); } } ``` 尽管 `Vector` 易于使用,但由于其较低的并发性和灵活性不足,现代开发中更推荐其他替代方案。 --- #### 3. 使用 `CopyOnWriteArrayList` `CopyOnWriteArrayList` 是另一种高效的线程安全 `List` 实现。它的主要特点是写操作时会复制底层数组,从而避免了对共享资源的竞争锁定。这种设计非常适合读多写少的场景[^4]。 下面展示了如何使用 `CopyOnWriteArrayList`: ```java import java.util.concurrent.CopyOnWriteArrayList; public class CopyOnWriteArrayListExample { public static void main(String[] args) { CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>(); cowList.add("Item1"); cowList.add("Item2"); for (String item : cowList) { System.out.println(item); } cowList.remove("Item1"); } } ``` 值得注意的是,由于每次写操作都会触发数组的复制,因此当列表较大或者频繁更新时,可能会带来较大的开销[^3]。 --- #### 性能对比与适用场景分析 | 方案 | 并发性能 | 修改成本 | 场景建议 | |---------------------|---------------|--------------|----------------------------| | `Collections.synchronizedList` | 较低 | 中等 | 小规模、偶尔使用的线程安全需求 | | `Vector` | 很低 | 高 | 不推荐;仅限遗留系统兼容 | | `CopyOnWriteArrayList` | 高 | 高 | 多读少写的高并发场景 | 从表中可以看出,不同的实现适用于不同类型的业务需求。对于大多数高性能应用而言,`CopyOnWriteArrayList` 更具优势,但在大规模数据集上的频繁写入操作可能导致性能瓶颈[^4]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值