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



目录
相关文章
|
4天前
|
安全 Java 开发者
【JAVA】哪些集合类是线程安全的
【JAVA】哪些集合类是线程安全的
|
1月前
|
安全 Java
Java中的线程安全集合
【4月更文挑战第1天】在多线程环境下,为了保证数据的安全性和一致性,我们需要使用线程安全集合。本文将介绍Java中常用的线程安全集合及其使用方法。
|
10月前
|
存储 安全 算法
一天一个 JUC 工具类 -- 并发集合
使用JUC工具包中的并发集合,我们可以避免手动处理锁和同步的复杂性,从而降低出现线程安全问题的概率。这些并发集合通过内部采用高效的算法和数据结构来优化并发操作,从而提供更好的性能和扩展性。
|
5月前
|
安全 Java 定位技术
Java中 ConcurrentHashMap 如何实现线程安全?
Java中 ConcurrentHashMap 如何实现线程安全?
47 0
|
7月前
|
安全 Java 索引
JUC第十六讲:JUC集合: CopyOnWriteArrayList详解
JUC第十六讲:JUC集合: CopyOnWriteArrayList详解
|
10月前
|
存储 缓存 监控
【Java面试】说说线程安全问题,以及Java里面一般用那些机制保证线程安全
【Java面试】说说线程安全问题,以及Java里面一般用那些机制保证线程安全
60 0
|
11月前
|
安全
JUC-集合
JUC-集合
45 0
|
11月前
|
安全 Java 程序员
【JavaEE】Callable接口(NO.6线程创建方法)-JUC的常见类-与线程安全有关集合类
JavaEE & Callable接口(NO.6线程创建方法) & JUC的常见组件 & 与线程安全有关类和集合类
32 0
|
11月前
|
安全 算法 Java
Java中线程安全的集合
Java中线程安全的集合
146 0
|
12月前
|
存储 安全 Java
【JUC基础】11. 并发下的集合类
我们直到ArrayList,HashMap等是线程不安全的容器。但是我们通常会频繁的在JUC中使用集合类,那么应该如何确保线程安全?