JUC下验证解决集合类不安全

简介: JUC下验证解决集合类不安全

我们平常使用HashMap,ArrayList觉得安全是因为是单线程的,它们在多线程下并不安全

JUC并发,在JUC看来,这些集合都是不安全的

  1. List不安全

单线程的情况下没有问题


package com.wyh.unSafe;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
 * @program: JUC
 * @description: 不安全的List
 * @author: 魏一鹤
 * @createDate: 2022-02-14 22:33
 **/
public class ListUnSafe {
public static void main(String[] args){
//初始化list
        List<String> list = Arrays.asList("1", "2", "3");
//forEach循环打印 forEach的参数是一个函数式接口
        list.forEach(System.out::println);
//相当于以下输出写法
        //for (String s : list) {
        //    System.out.println(s);
        //}
    }
    }


1

2

3


多线程下发现问题


package com.wyh.unSafe;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
/**
 * @program: JUC
 * @description: 不安全的List 多线程
 * @author: 魏一鹤
 * @createDate: 2022-02-14 22:33
 **/
//多线程操作List
//并发下的集合都会出这个错  java.util.ConcurrentModificationException 并发修改异常
public class ListUnSafe2 {
public static void main(String[] args){
//初始化list 并发下list是不安全的
       ArrayList<String> arrayList=new ArrayList<String>();
//循环添加一些字符串
        for (int i = 1; i <= 10; i++) {
//10个线程去一起并发添加
            new Thread(()->{
//uuid随机生成的字符串并且截取前五位字符串
                arrayList.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(arrayList);
            },String.valueOf(i)).start();
        }
    }
}

报错

[null, a37dc, 96275]

[null, a37dc, 96275, e061d, 5d2c7, 80856, 2c464, 72ba5, 29bd1, 2ea0a]

[null, a37dc, 96275, e061d, 5d2c7]

[null, a37dc, 96275, e061d, 5d2c7, 80856, 2c464, 72ba5]

[null, a37dc, 96275, e061d, 5d2c7, 80856, 2c464]

Exception in thread "Thread-7" [null, a37dc, 96275, e061d]

[null, a37dc, 96275, e061d, 5d2c7, 80856]

[null, a37dc, 96275]

[null, a37dc, 96275]

java.util.ConcurrentModificationException

       at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)

       at java.util.ArrayList$Itr.next(ArrayList.java:861)

       at java.util.AbstractCollection.toString(AbstractCollection.java:461)

       at java.lang.String.valueOf(String.java:2994)

       at java.io.PrintStream.println(PrintStream.java:821)

       at com.wyh.unSafe.ListUnSafe2.lambda$main$0(ListUnSafe2.java:28)

       at java.lang.Thread.run(Thread.java:748)



注意这个异常 并发下的集合都会出这个错  java.util.ConcurrentModificationException:并发修改异常

那么既然List并发不安全,我们应该如何解决呢


  1. 使用Vector
package com.wyh.unSafe;
import java.util.*;
/**
 * @program: JUC
 * @description: 不安全的List 多线程
 * @author: 魏一鹤
 * @createDate: 2022-02-14 22:33
 **/
//多线程操作List
//并发下的集合都会出这个错  java.util.ConcurrentModificationException 并发修改异常
public class ListUnSafe2 {
public static void main(String[] args){
/**
         * 那么既然List并发不安全,我们应该如何解决呢
         *  1 把ArrayList换成Vector Vector默认就是安全的(不建议使用 因为涉及内存问题)
         *  
        **/
//初始化list 并发下list是不安全的 但是Vector默认就是安全的
        List<String> arrayList = new Vector<>();
//循环添加一些字符串
        for (int i = 1; i <= 10; i++) {
//10个线程去一起并发添加
            new Thread(()->{
//uuid随机生成的字符串并且截取前五位字符串
                arrayList.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(arrayList);
            },String.valueOf(i)).start();
        }
    }
}

[4a075, 9cf3d, 0d593]

[4a075, 9cf3d, 0d593, 1a746, 180e5, c0761, ebf2c, eadb4, a43e2, fc728]

[4a075, 9cf3d, 0d593, 1a746, 180e5, c0761, ebf2c, eadb4, a43e2, fc728]

[4a075, 9cf3d, 0d593, 1a746, 180e5, c0761, ebf2c, eadb4, a43e2, fc728]

[4a075, 9cf3d, 0d593, 1a746, 180e5, c0761, ebf2c, eadb4, a43e2]

[4a075, 9cf3d, 0d593, 1a746, 180e5, c0761, ebf2c, eadb4]

[4a075, 9cf3d, 0d593, 1a746, 180e5, c0761, ebf2c]


  1. 利用Collection工具类来转换安全的List 不止可以生成线程安全的List 还可以生成线程安全的Map Set

[4a075, 9cf3d, 0d593, 1a746, 180e5, c0761]

[4a075, 9cf3d, 0d593, 1a746, 180e5]

[4a075, 9cf3d, 0d593, 1a746]


package com.wyh.unSafe;
import java.util.*;
/**
 * @program: JUC
 * @description: 不安全的List 多线程
 * @author: 魏一鹤
 * @createDate: 2022-02-14 22:33
 **/
//多线程操作List
//并发下的集合都会出这个错  java.util.ConcurrentModificationException 并发修改异常
public class ListUnSafe2 {
public static void main(String[] args){
/**
         * 那么既然List并发不安全,我们应该如何解决呢
         *  1 把ArrayList换成Vector Vector默认就是安全的(不建议使用 因为涉及内存问题)
         *  2 利用Collection工具类来转换安全的List 不止可以生成线程安全的List 还可以生成线程安全的Map Set
         **/
        //使用Collections的synchronizedList方法返回一个新的线程安全带的List
        List<Object> arrayList = Collections.synchronizedList(new ArrayList<>());
//循环添加一些字符串
        for (int i = 1; i <= 10; i++) {
//10个线程去一起并发添加
            new Thread(()->{
//uuid随机生成的字符串并且截取前五位字符串
                arrayList.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(arrayList);
            },String.valueOf(i)).start();
        }
    }
}

[de36a, d1853, 1ffee]

[de36a, d1853, 1ffee, 381b9, 838fe, 10cf0, 42b85, 68cce, 1a592]

[de36a, d1853, 1ffee, 381b9, 838fe, 10cf0, 42b85, 68cce]

[de36a, d1853, 1ffee, 381b9, 838fe, 10cf0, 42b85]

[de36a, d1853, 1ffee, 381b9]

[de36a, d1853, 1ffee, 381b9, 838fe, 10cf0]

[de36a, d1853, 1ffee, 381b9, 838fe]

[de36a, d1853, 1ffee, 381b9]

[de36a, d1853, 1ffee]

[de36a, d1853, 1ffee, 381b9, 838fe, 10cf0, 42b85, 68cce, 1a592, 21ee9]



  1. 以上两种方法属于普通层面

以下这种属于JUC的,推荐使用JUC下的CopyOnWritrArrayList


package com.wyh.unSafe;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
 * @program: JUC
 * @description: 不安全的List 多线程
 * @author: 魏一鹤
 * @createDate: 2022-02-14 22:33
 **/
//多线程操作List
//并发下的集合都会出这个错  java.util.ConcurrentModificationException 并发修改异常
public class ListUnSafe2 {
public static void main(String[] args){
/**
         * 那么既然List并发不安全,我们应该如何解决呢
         *  1 把ArrayList换成Vector Vector默认就是安全的(不建议使用 因为涉及内存问题)
         *  2 利用Collection工具类来转换安全的List 不止可以生成线程安全的List 还可以生成线程安全的Map Set
         *  3 使用JUC下的CopyOnWriteArrayList 当然也有线程安全的CopyOnWriteArraySet
         **/
        //使用JUC下的CopyOnWriteArrayLis  它是一个线程安全的List
        //CopyOnWrite:写入时复制 又叫COW(CopyOnWrite)思想  它是计算机设计领域的一种优化策略
        //在写入的时候避免覆盖,造成数据问题  读写分离  写入的时候先复制出来,写入完之后再插入进去 保证线程安全
        List<Object> arrayList =new CopyOnWriteArrayList<>();
//循环添加一些字符串
        for (int i = 1; i <= 10; i++) {
//10个线程去一起并发添加
            new Thread(()->{
//uuid随机生成的字符串并且截取前五位字符串
                arrayList.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(arrayList);
            },String.valueOf(i)).start();
        }
    }
}


[3837d, 70019, bf585, 4d62a, 7575d]

[3837d, 70019, bf585, 4d62a, 7575d, a4ae9, 34025, 3b3d0]

[3837d, 70019, bf585, 4d62a, 7575d, a4ae9, 34025]

[3837d, 70019, bf585, 4d62a]

[3837d, 70019, bf585, 4d62a, 7575d, a4ae9]

[3837d, 70019, bf585, 4d62a]

[3837d, 70019, bf585, 4d62a]

[3837d, 70019, bf585, 4d62a, 7575d, a4ae9, 34025, 3b3d0]

[3837d, 70019, bf585, 4d62a, 7575d, a4ae9, 34025, 3b3d0, 5edaa, 45311]

[3837d, 70019, bf585, 4d62a, 7575d, a4ae9, 34025, 3b3d0, 5edaa]


那么为什么在并发的情况下使用CopyOnWritrArrayList就线程安全呢?

通过查看源码发现它也是使用一个数组,不过这个数组是被transient(有序的)和volatile(唯一的 )进行修饰的


image.png



目录
相关文章
|
10天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
6月前
|
编解码 安全 算法
Java多线程基础-18:线程安全的集合类与ConcurrentHashMap
如果这些单线程中的集合类确实需要在多线程中使用,该怎么办呢?思路有两个: 最直接的方式:使用锁,手动保证。如多个线程修改ArrayList对象,此时就可能有问题,就可以给修改操作进行加锁。但手动加锁的方式并不是很方便,因此标准库还提供了一些线程安全的集合类。
98 4
|
6月前
|
安全 Java 容器
Java 多线程系列Ⅶ(线程安全集合类)
Java 多线程系列Ⅶ(线程安全集合类)
|
5月前
|
安全 Java 容器
多线程(进阶四:线程安全的集合类)
多线程(进阶四:线程安全的集合类)
34 0
|
6月前
|
存储 安全 Java
Java并发基础:CopyOnWriteArrayList全面解析
CopyOnWriteArrayList类的最大优点在于读取时无需加锁,非常适合读多写少的并发场景,由于其写操作通过复制底层数据来实现,从而保证了读取数据的一致性和高效性,此外,它简单易用,是快速实现线程安全列表的不错选择,CopyOnWriteArrayList在读操作占主导的场景下,能够提供出色的性能和稳定性。
142 1
Java并发基础:CopyOnWriteArrayList全面解析
|
存储 安全 算法
一天一个 JUC 工具类 -- 并发集合
使用JUC工具包中的并发集合,我们可以避免手动处理锁和同步的复杂性,从而降低出现线程安全问题的概率。这些并发集合通过内部采用高效的算法和数据结构来优化并发操作,从而提供更好的性能和扩展性。
|
11月前
|
安全 Java 定位技术
Java中 ConcurrentHashMap 如何实现线程安全?
Java中 ConcurrentHashMap 如何实现线程安全?
80 0
|
算法 Java 容器
深入探究Java集合工具类Collections的神奇功能
深入探究Java集合工具类Collections的神奇功能
|
安全 Java 索引
JUC第十六讲:JUC集合: CopyOnWriteArrayList详解
JUC第十六讲:JUC集合: CopyOnWriteArrayList详解
|
安全 算法 Java
【Java面试宝典】线程安全问题|线程死锁的出现|线程安全的集合类
【Java面试宝典】线程安全问题|线程死锁的出现|线程安全的集合类
129 0