Java多线程编程中的线程安全集合:保护数据的铁壁

简介: Java多线程编程中的线程安全集合:保护数据的铁壁

前言


Java多线程编程是现代软件开发的重要组成部分,然而,多线程环境下数据的安全性一直是一个棘手的问题。本文将探讨如何通过线程安全集合来解决这一挑战。我们将深入研究Java中的Concurrent包,介绍诸如ConcurrentHashMap、CopyOnWriteArrayList等强大的数据结构,它们为多线程应用提供了高效的数据管理方式。无论您是初学者还是有经验的开发人员,都将从本文中学到如何确保数据在多线程环境下的安全性,为您的Java多线程应用程序打造坚实的基础。




线程安全集合


CopyOnWriteArrayList重点


  • 线程安全的ArrayList,加强版读写分离。
  • 写有锁,读无锁,读写之间不阻塞,优于读写锁。
  • 写入时,先copy一个容器副本、再添加新元素,最后替换引用。
  • 使用方式与ArrayList无异。

示例:

public class TestCopyOnWriteArrayList {
  public static void main(String[] args) {
    //1创建集合
    CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<>();
    //2使用多线程操作
    ExecutorService es=Executors.newFixedThreadPool(5);
    //3提交任务
    for(int i=0;i<5;i++) {
      es.submit(new Runnable() {
        @Override
        public void run() {
          for(int j=0;j<10;j++) {
            list.add(Thread.currentThread().getName()+"...."+new Random().nextInt(1000));
          }
        }
      });
    }
    //4关闭线程池
    es.shutdown();
    while(!es.isTerminated()) {}
    //5打印结果
    System.out.println("元素个数:"+list.size());
    for (String string : list) {
      System.out.println(string);
    }
  }
}


CopyOnWriteArrayList如何做到线程安全的


CopyOnWriteArrayList使用了一种叫写时复制的方法,当有新元素添加到CopyOnWriteArrayList时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组。

当有新元素加入的时候,如下图,创建新数组,并往新数组中加入一个新元素,这个时候,array这个引用仍然是指向原数组的。


当元素在新数组添加成功后,将array这个引用指向新数组。

CopyOnWriteArrayList的整个add操作都是在的保护下进行的。 这样做是为了避免在多线程并发add的时候,复制出多个副本出来,把数据搞乱了,导致最终的数组数据不是我们期望的。


CopyOnWriteArrayListadd操作的源代码如下:

public boolean add(E e) {
    //1、先加锁
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        //2、拷贝数组
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        //3、将元素加入到新数组中
        newElements[len] = e;
        //4、将array引用指向到新数组
        setArray(newElements);
        return true;
    } finally {
       //5、解锁
        lock.unlock();
    }
}

由于所有的写操作都是在新数组进行的,这个时候如果有线程并发的写,则通过锁来控制,如果有线程并发的读,则分几种情况:


1、如果写操作未完成,那么直接读取原数组的数据;


2、如果写操作完成,但是引用还未指向新数组,那么也是读取原数组数据;


3、如果写操作完成,并且引用已经指向了新的数组,那么直接从新数组中读取数据。

可见,CopyOnWriteArrayList读操作是可以不用加锁的。




CopyOnWriteArraySet


示例:

public class TestCopyOnWriteArraySet {
  public static void main(String[] args) {
    //1创建集合
    CopyOnWriteArraySet<String> set=new CopyOnWriteArraySet<>();
    //2添加元素
    set.add("pingguo");
    set.add("huawei");
    set.add("xiaomi");
    set.add("lianxiang");
    set.add("pingguo");
    //3打印
    System.out.println("元素个数:"+set.size());
    System.out.println(set.toString());
  }
}


ConcurrentHashMap重点


  • 初始容量默认为16段(Segment),使用分段锁设计。
  • 不对整个Map加锁,而是为每个Segment加锁。
  • 当多个对象存入同一个Segment时,才需要互斥。
  • 最理想状态为16个对象分别存入16个Segment,并行数量16。
  • 使用方式与HashMap无异。

注意⚠️: ConcurrentHashMap jdk1.8之前才是分段锁,1.8之后没有使用分段锁了,而是乐观锁加Synchronized,这里注意一下

示例:

public class TestConcurrentHashMap {
  public static void main(String[] args) {
    //1创建集合
    ConcurrentHashMap<String, String> hashMap=new ConcurrentHashMap<String, String>();
    //2使用多线程添加数据
    for(int i=0;i<5;i++) {
      new Thread(new Runnable() {
        @Override
        public void run() {
          for(int k=0;k<10;k++) {
            hashMap.put(Thread.currentThread().getName()+"--"+k, k+"");
            System.out.println(hashMap);
          }
        }
      }).start();
    }
  }
}




最后


本期结束咱们下次再见👋~

🌊 关注我不迷路,如果本篇文章对你有所帮助,或者你有什么疑问,欢迎在评论区留言,我一般看到都会回复的。大家点赞支持一下哟~ 💗

相关文章
|
2月前
|
Oracle Java 关系型数据库
掌握Java Stream API:高效集合处理的利器
掌握Java Stream API:高效集合处理的利器
329 80
|
2月前
|
并行计算 Java API
Java List 集合结合 Java 17 新特性与现代开发实践的深度解析及实战指南 Java List 集合
本文深入解析Java 17中List集合的现代用法,结合函数式编程、Stream API、密封类、模式匹配等新特性,通过实操案例讲解数据处理、并行计算、响应式编程等场景下的高级应用,帮助开发者提升集合操作效率与代码质量。
124 1
|
2月前
|
存储 缓存 NoSQL
java 集合入门基础理论的核心概念与实用长尾知识
本文介绍了Java集合框架的基础理论知识,包括单列集合(List、Set、Queue)和双列集合(Map)的特点及常用实现类(如ArrayList、HashSet、HashMap等)。详细讲解了集合的遍历方式(迭代器、增强for循环、Lambda表达式)和典型应用场景(如数据去重、键值存储等)。通过具体代码示例,帮助初学者理解集合框架的核心概念和实际应用,为Java编程中的数据存储与管理提供基础指导。
73 0
|
2月前
|
安全 Java API
Java 集合高级应用与实战技巧之高效运用方法及实战案例解析
本课程深入讲解Java集合的高级应用与实战技巧,涵盖Stream API、并行处理、Optional类、现代化Map操作、不可变集合、异步处理及高级排序等核心内容,结合丰富示例,助你掌握Java集合的高效运用,提升代码质量与开发效率。
182 0
|
2月前
|
存储 安全 Java
Java 学习路线 35 掌握 List 集合从入门到精通的 List 集合核心知识
本文详细解析Java中List集合的原理、常用实现类(如ArrayList、LinkedList)、核心方法及遍历方式,并结合数据去重、排序等实际应用场景,帮助开发者掌握List在不同业务场景下的高效使用,提升Java编程能力。
281 0
|
Java C语言 C++
Java 的数据类型划分(数据类型划分)| 学习笔记
快速学习 Java 的数据类型划分(数据类型划分)
174 0
Java 的数据类型划分(数据类型划分)| 学习笔记
|
Java 开发者 Windows
Java 数据类型划分(字符型)|学习笔记
快速学习 Java 数据类型划分(字符型)
175 0
|
Java 开发者
Java 数据类型划分(整型类型)|学习笔记
快速学习 Java 数据类型划分(整型类型)
139 0
|
Java 开发者
Java 数据类型划分(初见 String 类)|学习笔记
快速学习 Java 数据类型划分(初见 String 类)
137 0
|
Java 开发者
Java 数据类型划分(布尔型)|学习笔记
快速学习 Java 数据类型划分(布尔型)
144 0