老哥们,有个多线程的问题,我想了半天也没想明白,求解答
java吧
全部回复
仅看楼主
level 5
这是程序:
public class SafeTest {
static class ThreadSafe {
ArrayList<String> list = new ArrayList<>();
public final void method1(int loopNumber) {
for (int i = 0; i < loopNumber; i++) {
method2(list);
method3(list);
}
}
private void method2(ArrayList<String> list) {
list.add("1");
}
private void method3(ArrayList<String> list) {
list.remove(0);
}
}
static final int THREAD_NUMBER = 2;
static final int LOOP_NUMBER = 200;
public static void main(String[] args) {
ThreadSafe test = new ThreadSafe();
for (int i = 0; i < THREAD_NUMBER; i++) {
new Thread(() -> {
test.method1(LOOP_NUMBER);
},
"Thread" + i).start();
}
}
这是报错:
Exception in thread "Thread0" Exception in thread "Thread1" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.remove(ArrayList.java:507)
at org.example.SafeTest$ThreadSafe.method3(SafeTest.java:23)
at org.example.SafeTest$ThreadSafe.method1(SafeTest.java:16)
at org.example.SafeTest.lambda$main$0(SafeTest.java:36)
at java.lang.Thread.run(Thread.java:750)
java.lang.IndexOutOfBoundsException: Index: 0, Size: -1
at java.util.ArrayList.rangeCheck(ArrayList.java:659)
at java.util.ArrayList.remove(ArrayList.java:498)
at org.example.SafeTest$ThreadSafe.method3(SafeTest.java:23)
at org.example.SafeTest$ThreadSafe.method1(SafeTest.java:16)
at org.example.SafeTest.lambda$main$0(SafeTest.java:36)
at java.lang.Thread.run(Thread.java:750)
}
2026年03月14日 13点03分 1
level 5
我不明白,是个什么样的场景会导致出现,数组越界。
2026年03月14日 13点03分 2
level 5
public class SafeTest {
static class ThreadSafe {
ArrayList<String> list = new ArrayList<>();
public final void method1(int loopNumber) {
for (int i = 0; i < loopNumber; i++) {
method2(list);
method3(list);
}
}
private void method2(ArrayList<String> list) {
list.add("1");
}
private void method3(ArrayList<String> list) {
list.remove(0);
}
}
static final int THREAD_NUMBER = 2;
static final int LOOP_NUMBER = 200;
public static void main(String[] args) {
ThreadSafe test = new ThreadSafe();
for (int i = 0; i < THREAD_NUMBER; i++) {
new Thread(() -> {
test.method1(LOOP_NUMBER);
},
"Thread" + i).start();
}
}
}
2026年03月14日 13点03分 3
level 5
都快把AI累死了,没说个所以然来
2026年03月14日 13点03分 4
level 9
我看了下,这个是县城加1超过了那个集合大小,所以越界
2026年03月14日 13点03分 5
老哥能展开说说吗?
2026年03月14日 13点03分
你为啥要写这么无聊的代码
2026年03月14日 13点03分
@好人就是俺大锤 原来的学习笔记,现在拿出来研究
2026年03月14日 13点03分
@不去明知山🉐 这种笔记毫无意义,真的
2026年03月14日 13点03分
level 5
arraylist 并不是线程安全的,你这个案例只是演示了一下,并发修改同一个列表会出现什么错误?
这很正常,就是类内部维护的数组索引,在并发修改情况下出错了。
本质上和那个多线程去修改同一个变量,可能导致更新丢失没啥区别。
2026年03月14日 14点03分 6
对,我当时就是没想白从哪开始想,一提索引我就有方向了
2026年03月14日 14点03分
level 9
还没看,先提个建议。以后不要复制代码原文给别人。直接截图IDE界面更好看
2026年03月14日 14点03分 7
好的听劝,下次问问题会再体面一些[呵呵]
2026年03月14日 14点03分
level 6
list线程不安全 数据超过容器长度扩容会覆盖原来对象数据
2026年03月14日 14点03分 8
这时添加的数据长度小于要移出的长度 就溢出了
2026年03月14日 14点03分
@🌼我是绅士 感谢老哥,我明天看看
2026年03月14日 14点03分
@不去明知山🉐 单线程扩容没问题 多线程就可能并发同时扩容 覆盖了其他线程已经扩容的对象 这时数组实际长度就短了
2026年03月14日 14点03分
level 9
不去翻源码没人能解答得了。不过肯定是和ArrayList扩容有关。研究这个问题没意义,因为多线程场景本来就不可能用ArrayList
2026年03月14日 14点03分 9
感谢老哥给思路,八成就是这个事,我明天再看看
2026年03月14日 14点03分
level 1
Array list remove(0)方法的时候,它会把内部整个数组往左移,然后把最后一个元素置为null,即array(--size)=null ,场景是两个线程同时进到了remove方法内,线程1把数据删了,size变成0,然后线程2取--size的时候就变成了array(-1),就报了这个索引越界的错
2026年03月14日 14点03分 10
@不去明知山🉐 也是size的问题啊,add方法是往数组尾端去加数据,array(size++)=ele 两个线程在往这个数组里面加数据的时候,size读的都是0,然后导致数组里只有一个数据 再往后就是我上面说的这样
2026年03月14日 15点03分
这个也是我当时有点迷惑的点之一,就是他是先加后删,怎么个场景下,会同时在列表为空的情况下,同时发生删除[小乖]
2026年03月14日 14点03分
level 1
大模型哪里不行了…这不是给你说的明明白白。ArrayList非线程安全,多线程操作可能导致ArrayList内部状态不一致而报错。
2026年03月14日 17点03分 11
level 1
多线程不一定,a线程跑完才跑b线程,有可能是线程跑1次,b线程跑n次,那就出现数组越界了
2026年03月16日 01点03分 13
level 1
这代码里加一句,在b线程里加一句if(!list.isEmpty)就不报错了
2026年03月16日 01点03分 14
level 3
多线程就用线程安全的list啊 List<String> list = new CopyOnWriteArrayList<>();
或者你手动加锁
2026年03月16日 04点03分 15
level 7
感觉问题大概率出现在拷贝的时候,如果a remove在拷贝的时候阻塞了,b remove全部执行完成,这时a的拷贝就会出错,具体还得结合arraylist和system.arraycopy源码分析一下
2026年03月16日 04点03分 16
1 2 尾页