Java JUC中操作List安全类的集合案例

作者:专注写bug 时间:2022-10-28 11:09:31 

不安全的集合

在单线程应用中,通常采取new ArrayList(),指定一个List集合,用于存放可重复的数据。

但在多线程下,往往会出现意想不到的问题,代码如下所示:


import java.util.*;
public class ListTest {
   public static void main(String[] args) throws InterruptedException {
       // 创建list集合
       //List<String> lists = Arrays.asList("1", "2", "3");
       // 不安全
       List<String> lists = new ArrayList<>();

// 开启十个线程增加数据
       for (int i = 1; i <= 40; i++) {
           new Thread(()->{
               lists.add(UUID.randomUUID().toString().substring(0,5));
               System.out.println(Thread.currentThread().getName()+"=="+lists);
           },String.valueOf(i)).start();
       }
   }
}

其运行结果如下所示:

Java JUC中操作List安全类的集合案例

多线程操作同一集合对象信息,往往会出现java.util.ConcurrentModificationException异常报错信息。

Java中提供的安全措施

在java语言中,提供了一种新的List集合,java.util.Vector类,具体看下列代码:


import java.util.*;
public class ListTest {
   public static void main(String[] args) throws InterruptedException {
       // 创建list集合
       //List<String> lists = Arrays.asList("1", "2", "3");
       // 不安全
       //List<String> lists = new ArrayList<>();
List<String> lists = new Vector<>();

// 开启十个线程增加数据
       for (int i = 1; i <= 40; i++) {
           new Thread(()->{
               lists.add(UUID.randomUUID().toString().substring(0,5));
               System.out.println(Thread.currentThread().getName()+"=="+lists);
           },String.valueOf(i)).start();
       }
   }
}

运行日志如下所示:

Java JUC中操作List安全类的集合案例

不会出现java.util.ConcurrentModificationException报错信息。

为什么能保证数据的安全操作?

Java JUC中操作List安全类的集合案例

采取了 synchronized 针对方法执行调用者加锁,保证add操作的多线程安全性!

JUC下的安全List集合

在JUC包下,提供有以下几种创建安全集合的方式。

  • 方式一:Collections.synchronizedList(new ArrayList<>());


import java.util.*;
public class ListTest {
   public static void main(String[] args) throws InterruptedException {
List<String> lists = Collections.synchronizedList(new ArrayList<>());

// 开启十个线程增加数据
       for (int i = 1; i <= 40; i++) {
           new Thread(()->{
               lists.add(UUID.randomUUID().toString().substring(0,5));
               System.out.println(Thread.currentThread().getName()+"=="+lists);
           },String.valueOf(i)).start();
       }
   }
}

查看底层源码实现逻辑

Java JUC中操作List安全类的集合案例

判断传入的 list 集合类型,判断类型是否为 java.util.RandomAccess,如果是则采取java.util.Collections.SynchronizedRandomAccessList构造集合,如果不是则采取java.util.Collections.SynchronizedList构造集合。

源码中对应的add操作逻辑如下所示:

Java JUC中操作List安全类的集合案例

采取synchronized同步代码块的方式,对数据的add操作实现加锁!

  • 方式二:new CopyOnWriteArrayList();


import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class ListTest {
   public static void main(String[] args) throws InterruptedException {
       List<String> lists = new CopyOnWriteArrayList<>();

// 开启十个线程增加数据
       for (int i = 1; i <= 40; i++) {
           new Thread(()->{
               lists.add(UUID.randomUUID().toString().substring(0,5));
               System.out.println(Thread.currentThread().getName()+"=="+lists);
           },String.valueOf(i)).start();
       }
   }
}

源码中的介绍如下:

Java JUC中操作List安全类的集合案例

Java JUC中操作List安全类的集合案例

显而易见,其逻辑如下所示:

  1. 调用add方法后,拿到java.util.concurrent.locks.ReentrantLock对象信息。

  2. 调用 lock.lock() 拿到锁!

  3. 将原数组对象copy操作,并创建原数组大小+1的新数组。

  4. 将新数据放入新数组中。

  5. 任何操作finally,都进行锁的释放!

性能方面

JUC包下的Lock操作,都比synchronized性能更好!

到此这篇关于JUC中操作List安全类的集合案例的文章就介绍到这了,更多相关JUC中List安全类内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

来源:https://blog.csdn.net/qq_38322527/article/details/114703142

标签:Java,JUC,List,安全类集合
0
投稿

猜你喜欢

  • 基于Springboot一个注解搞定数据字典的实践方案

    2022-12-23 01:12:38
  • Java数组的定义、初始化、及二维数组用法分析

    2022-06-11 16:59:04
  • 一篇带你解析入门LongAdder源码

    2023-11-28 20:17:52
  • SpringMVC基于配置的异常处理器

    2023-01-19 15:34:33
  • Android仿微信清理内存图表动画(解决surfaceView屏幕闪烁问题)demo实例详解

    2023-05-31 15:35:27
  • Java实现的日期处理类完整实例

    2023-12-08 00:16:10
  • 使用Java实现Redis限流的方法

    2023-09-27 01:43:47
  • 通过Java设置Word页面背景色过程详解

    2022-06-22 06:23:42
  • Unity实现倒计时组件

    2021-06-18 01:06:44
  • Android 快速实现防止网络重复请求&按钮重复点击的方法

    2023-08-29 17:31:45
  • EditText限制小数点前后位数的实例

    2023-04-10 03:56:14
  • Java如何实现单链表的增删改查

    2021-09-19 09:49:25
  • C#开发的人脸左右相似度计算软件源码分析

    2023-08-26 05:18:41
  • C#判断获取的是文件夹还是文件的实例

    2022-11-25 05:00:01
  • C#使用xsd文件验证XML格式是否正确的实现方法

    2022-02-08 11:11:09
  • Android学习之Broadcast的简单使用

    2023-11-19 15:18:02
  • spring的Cache注解和redis的区别说明

    2023-10-20 02:01:33
  • C#实现跑马灯效果的示例代码

    2022-06-10 07:12:40
  • Flutter集成高德地图并添加自定义Maker的实践

    2022-07-11 21:32:49
  • Java线程状态变换过程代码解析

    2023-08-06 18:05:29
  • asp之家 软件编程 m.aspxhome.com