【Java】ArrayList线程不安全的坑
- 作者: 五速梦信息网
- 时间: 2026年04月04日 13:56
问题复现:
使用Java的steam().paralleStream(),foreach()方法向ArrayList添加数据,导致ArrayList中出现空值,代码如下:
public static void main(String[] args) {
List<Integer> a = new ArrayList<>();
for (int i = 0; i < 20; i++) {
a.add(i);
}
List<String> a1 = new ArrayList<>();
a.parallelStream().forEach(x -> {
a1.add(String.valueOf(x));
});
System.out.println(a1);
}
输出结果:
[12, 6, 14, 5, 13, 8, 11, 9, 10, 7, 2, 17, 1, 4, 0, null, 19, 18, 16, 15]
如上,会出现null值
问题分析:
ArrayList通过size变量来控制当前数组元素的指针,代码:
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length) {
elementData = this.grow();
}
elementData[s] = e;
this.size = s + 1;
}
public boolean add(E e) {
++this.modCount;
this.add(e, this.elementData, this.size);
return true;
}
如果此时出现多线程操作,例如Thread1获取到size=3,对数组的第三个元素进行赋值,此时Thread2获取到的size也等于3,也对数组第三个元素进行赋值,此时Thread1和Thread2都操作的第三个元素,然后此时Thread1进行size+1操作,Thread2进行加size+1操作,当前size值为5,但是实际数组中只有4个元素,有一个为null,因为Thread2本来应该对数组第4个元素赋值,因为线程不安全导致拿到的size值为3
解决方式:
1.使用Vector,所有方法用synchronized修饰,数组结构
2.Collections.sychronizedList(list)的方式获取一个list的代理,不限于ArrayList,可以实现任意list子类的同步,对大部分操作代码块进行加锁,例如:add,set,get,foreach等,不过迭代器操作未加锁,依旧是线程不安全的
Fork/Join
4.CopyOnWriteArrayList,写操作单独创建一个list,读操作不加锁,适合读操作较多的场景
- 上一篇: 【Java】Junit快速入门
- 下一篇: 【Java 进阶】Java8 新特性的理解与应用
相关文章
-
【Java】Junit快速入门
【Java】Junit快速入门
- 互联网
- 2026年04月04日
-
【Java】分布式自增ID算法
【Java】分布式自增ID算法
- 互联网
- 2026年04月04日
-
【java】浅析java组件中的布局管理器
【java】浅析java组件中的布局管理器
- 互联网
- 2026年04月04日
-
【Java 进阶】Java8 新特性的理解与应用
【Java 进阶】Java8 新特性的理解与应用
- 互联网
- 2026年04月04日
-
【Java EE 学习 47】【Hibernate学习第四天】【sesion】【一级缓存】【懒加载】
【Java EE 学习 47】【Hibernate学习第四天】【sesion】【一级缓存】【懒加载】
- 互联网
- 2026年04月04日
-
【html5】Web存储
【html5】Web存储
- 互联网
- 2026年04月04日






