我多次运行以下代码,发现有时我从 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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
示例输出:
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
Run Code Online (Sandbox Code Playgroud)
我知道为什么总大小是 36。但我想知道为什么我在第 10 位得到空值。
注意:这并不是每次都会生成。您可能需要运行此代码 5 到 10 次才能生成此代码。
您遇到的情况称为竞争条件。
“竞赛”发生在实现您正在使用的集合对象的Java 运行时库代码中。(而且,到目前为止,你非常幸运,它没有让你的整个程序崩溃。下次,它很容易......情况不稳定。)
如果您打算在线程中使用容器类,则必须确保您使用的类是“线程安全的”,这意味着它们包含必要的逻辑,以允许它们同时被多个线程正确使用。 或者,您必须在整个应用程序中手动实现适当的互斥逻辑。ls.get()(主线程必须与子线程互锁,以便在线程同时执行操作时它不会尝试ls.add()。)
如果您使用的类不是线程安全的,有时您会看到应用程序定义了自己设计的“包装类”,该类在其互斥逻辑中“包装”对非线程安全类的调用自己的设计,以便包装器“是”线程安全的,至少对于应用程序来说是这样。
(PS:这个原则适用于任何编程语言。)
| 归档时间: |
|
| 查看次数: |
2718 次 |
| 最近记录: |