gpt4 book ai didi

java - 为什么在使用线程添加值后从 ArrayList 获取空值

转载 作者:行者123 更新时间:2023-11-30 06:52:41 25 4
gpt4 key购买 nike

我多次运行以下代码,发现有时我从 ArrayList 中获取“null”。当我向数组添加整数值时,我无法理解为什么会发生这种情况。

package com;

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

public class test implements Runnable {

static List<Integer> ls = new ArrayList<Integer>();

public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new test());
Thread t2 = new Thread(new test());

t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(ls.size());
for (int i = 0; i < ls.size(); ++i) {
System.out.println(i + " " + ls.get(i));
}
}

@Override
public synchronized void run() {
try {
for (int i = 0; i < 20; ++i) {
ls.add(i);
Thread.sleep(5);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

示例输出:

36  
0 0
1 0
2 1
3 1
4 2
5 2
6 3
7 3
8 4
9 4
**10 null**
11 5
12 6
13 6
14 7
15 7
16 8
17 8
18 9
19 9
20 10
21 10
22 11
23 11
24 12
25 12
26 13
27 14
28 15
29 16
30 16
31 17
32 17
33 18
34 19
35 19

我知道为什么总大小是 36。但我想知道为什么我在第 10 个位置得到 null。

注意:这不是每次都生成。您可能需要运行此代码 5 到 10 次才能生成此代码。

最佳答案

您遇到的是一种叫做竞争条件的东西。

“竞争”发生在实现您正在使用的集合对象的 Java 运行时库代码中。 (而且,到目前为止,你一直非常幸运它没有让你的整个程序崩溃。下一次,它很容易......情况不稳定。)

如果您打算在线程之间使用容器类,您必须确保您使用的类是“线程安全的”,这意味着它们包含必要的逻辑以允许它们同时被多个线程正确使用。 或者,您必须在整个应用程序中手动实现适当的互斥逻辑。 (主线程必须与子线程互锁,这样它就不会在线程同时执行 ls.add() 时尝试 ls.get()。)

如果您使用的类不是线程安全的,有时您会看到一个应用程序定义一个“包装类”,它自己设计“包装”调用非线程-安全类在其自己设计的互斥逻辑中,因此包装器"is"线程安全的,至少对于应用程序而言是这样。

(附言:此原则适用于任何编程语言。)

关于java - 为什么在使用线程添加值后从 ArrayList 获取空值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38531332/

25 4 0