首页 > 编程语言 > 详细

为什么ArrayList线程不安全?为什么ArrayList在多线程情况下会报ConcurrentModificationException?

时间:2021-05-13 19:49:56      阅读:17      评论:0      收藏:0      [点我收藏+]

 

看下面的第一个例子,并发读写:

package com.andy.juc;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class UnsafeList {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();

        System.out.println(list);
        for(int i=0;i<10;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    list.add(UUID.randomUUID().toString());
                    System.out.println(list);
                }
            },String.valueOf(i)).start();
        }
    }
}

 

上面的代码在System.out.println(list);这一行为报错,报错信息如下。

Exception in thread "0" Exception in thread "8" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    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.andy.juc.UnsafeList$1.run(UnsafeList.java:17)
    at java.lang.Thread.run(Thread.java:745)

 

原理如下,迭代器读next元素的时候,会检查modcount和最开始的modcount是不是一样的,相当于一个乐观锁。

技术分享图片

 

 

而在ArrayList的add方法里面,每次新增一个元素会把modcount给加1.

 

所以modcount修改之后,就会报这个错误。

 

 

 

需要注意的是,如果只是对ArrayList进行add操作,并不会发生ConcurrentModification报错,这个也是面试经常问的问题。

 

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class UnsafeList {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();

        System.out.println(list);
        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    list.add(UUID.randomUUID().toString());
                }
            },String.valueOf(i)).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list);
    }
}

 

扩展只是

为什么ArrayList底层用了数组,但是可以不用指定数组的大小?

因为ArrayList需要扩容,扩容的时候用了新的数组。

技术分享图片

 

 

 

 

 

技术分享图片

 

 

下面看一个ArrayList并发写的多线程问题,创建的size不是10000个,而是小于10000个:(多线程的例子一次有可能测不出效果,可以多试几次,或者增加线程个数)

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class UnsafeList {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();

        System.out.println(list);
        for(int i=0;i<10000;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    list.add(UUID.randomUUID().toString().substring(0,6));
                }
            },String.valueOf(i)).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
        System.out.println(list);
    }
}

 

执行结果如下:

技术分享图片

 

为什么ArrayList线程不安全?为什么ArrayList在多线程情况下会报ConcurrentModificationException?

原文:https://www.cnblogs.com/mkl34367803/p/14764102.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!