Java中如何安全地在多线程环境中修改集合

来源:苹果APP网作者:天马头衔:网络博主
导读:本期聚焦于小伙伴创作的《Java中如何安全地在多线程环境中修改集合》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java中如何安全地在多线程环境中修改集合》有用,将其分享出去将是对创作者最好的鼓励。

Java中普通集合如ArrayList、HashMap等都不是线程安全的,在多线程同时修改的场景下,可能会出现元素丢失、数据覆盖或者抛出ConcurrentModificationException异常的情况,因此需要采用特定的方式保证修改操作的安全性。

Java中如何安全地在多线程环境中修改集合

使用同步包装类实现线程安全修改

Java Collections工具类提供了同步包装方法,可以将普通集合包装成线程安全的集合,其核心原理是对集合的所有操作都加上同步锁,保证同一时间只有一个线程能修改集合。

常用的同步包装方法如下:

  • Collections.synchronizedList:包装List集合
  • Collections.synchronizedMap:包装Map集合
  • Collections.synchronizedSet:包装Set集合

以下是使用同步List修改元素的示例代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SynchronizedCollectionDemo {
    public static void main(String[] args) {
        // 创建普通ArrayList并包装为同步List
        List<Integer> syncList = Collections.synchronizedList(new ArrayList<>());
        
        // 创建10个线程同时向集合添加元素
        for (int i = 0; i < 10; i++) {
            int threadId = i;
            new Thread(() -> {
                for (int j = 0; j < 100; j++) {
                    syncList.add(threadId * 100 + j);
                }
            }).start();
        }
        
        // 等待所有线程执行完成
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        // 输出集合大小,结果应为1000
        System.out.println("集合元素数量:" + syncList.size());
    }
}

需要注意,同步包装类的迭代操作需要手动加锁,否则在迭代过程中如果有其他线程修改集合,依然会抛出并发修改异常。正确的迭代方式如下:

// 迭代同步List时需要手动加锁
synchronized (syncList) {
    for (Integer num : syncList) {
        System.out.println(num);
    }
}

使用并发容器实现线程安全修改

Java并发包java.util.concurrent中提供了大量内置线程安全的并发容器,相比同步包装类,它们的性能通常更好,且支持更多并发场景下的操作。

常用的并发容器包括:

  • CopyOnWriteArrayList:适合读多写少的List场景
  • ConcurrentHashMap:线程安全的Map实现,性能优于同步Map
  • ConcurrentLinkedQueue:线程安全的无界队列

以下是使用CopyOnWriteArrayList在多线程中修改集合的示例:

import java.util.concurrent.CopyOnWriteArrayList;

public class ConcurrentCollectionDemo {
    public static void main(String[] args) {
        // 创建并发List
        CopyOnWriteArrayList<Integer> concurrentList = new CopyOnWriteArrayList<>();
        
        // 创建10个线程同时添加元素
        for (int i = 0; i < 10; i++) {
            int threadId = i;
            new Thread(() -> {
                for (int j = 0; j < 100; j++) {
                    concurrentList.add(threadId * 100 + j);
                }
            }).start();
        }
        
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("并发List元素数量:" + concurrentList.size());
    }
}

CopyOnWriteArrayList的写操作会复制整个底层数组,因此写性能较差,但读操作不需要加锁,适合读多写少的场景。而ConcurrentHashMap采用分段锁或CAS机制实现线程安全,读写性能都比较优异,是多线程场景下Map的首选实现。

手动加锁控制集合修改

如果需要在修改集合时执行额外的逻辑,或者需要更细粒度的锁控制,也可以手动使用synchronized关键字或者ReentrantLock来加锁,保证修改操作的原子性。

以下是使用ReentrantLock手动加锁修改集合的示例:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

public class ManualLockDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        ReentrantLock lock = new ReentrantLock();
        
        for (int i = 0; i < 10; i++) {
            int threadId = i;
            new Thread(() -> {
                for (int j = 0; j < 100; j++) {
                    lock.lock();
                    try {
                        // 加锁后执行修改操作,还可以添加其他自定义逻辑
                        list.add(threadId * 100 + j);
                        // 比如打印当前集合大小
                        System.out.println("当前线程添加后集合大小:" + list.size());
                    } finally {
                        lock.unlock();
                    }
                }
            }).start();
        }
        
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("最终集合元素数量:" + list.size());
    }
}

不同方案对比

以下是几种线程安全修改集合方案的对比:

方案适用场景性能注意事项
同步包装类简单的多线程修改场景,不需要复杂并发操作一般,所有操作都加全局锁迭代需要手动加锁
并发容器高并发场景,尤其是读多写少或Map操作较好,采用更高效的并发控制机制不同容器特性不同,需根据场景选择
手动加锁需要自定义修改逻辑,或细粒度锁控制取决于锁的实现和使用方式需要注意锁的释放,避免死锁

注意事项

无论使用哪种方案,都需要注意以下几点:

  • 不要对线程安全的集合进行非原子性的复合操作,比如先判断集合是否存在元素再添加,这类操作依然需要额外加锁保证原子性
  • 根据业务场景选择合适的方案,读多写少优先选CopyOnWriteArrayList,Map操作优先选ConcurrentHashMap
  • 避免将普通集合直接暴露给多线程修改,即使初期是单线程使用,后续扩展也可能引发并发问题

Java多线程集合线程安全synchronized修改时间:2026-07-05 12:09:25

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。