Java 集合ArrayList 并发add

Java 8中多线程对ArrayList 进行添加元素的时候,有概率某个位置会出现null值,也可能缺少元素。我觉得应该是扩容那块出现问题。

public class ThreadTestArrayList {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(500);
        LatchDemo ld = new LatchDemo(latch);
        for (int i = 0; i < 500; i++) {
            new Thread(ld).start();
        }
        latch.await();
        ld.prif();
    }
}

class LatchDemo implements Runnable {

    public CountDownLatch latch;
    public List<Integer> list = new ArrayList<>();

    public LatchDemo(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
      //  synchronized (this){
        try {
            list.add(0);
        } finally {
            latch.countDown();
        }
        //}
    }

    public void prif() {
        System.out.println(list);
        System.out.println(list.size());
    }
}

CountDownLatch 这个是JUC里面的闭锁,这里的意思就是让main线程等待,让其他线程先执行add完毕后,main线程再执行打印,不然输出就不会准确。结果如下:
在这里插入图片描述

  1. 少元素的原因,可能是同一个数组位置被覆盖了,因为size++并不是原子性的,所以可能线程A自增的时候,A的cpu时间片用完了,然后线程B也进行一次自增,导致A的自增被覆盖了,所以先完成的线程更新的数据会被后完成的线程覆盖掉。
  2. 出现null的原因,Java8中,直接new ArrayList<>()实例化的时候,底层的数组是空的,大小为0,也就是第一次add会进行扩容的。假设现在有线程A和B分别要插入元素1和2,线程A调用add方法时,会进行它自己的扩容,在自己的工作空间创建新数组,这时A扩容未完成呢,此时线程B调用add方法时发现也需要,这时B也会进行扩容也创建自己的数组==(重点:这里都是在自己空间创建数组)==,假设此时线程A比线程B扩容先完成,此时list的elementDate是新的数组(A构建的),接着执行赋值操作elementDate[size++] = 1,在此之前线程B扩容 拿到的数组仍然是旧的elementDate,于是线程B构造一个新的数组(数据全部为null),然后使list的elementDate指向线程B构造的数组,那么线程A之前的elementDate也就被丢掉了,但是由于size已经自增,所以线程B会在下一个位置赋予2,那么此时数组元素就成了[null,2,x,x,x,x,x,x,x]
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值