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

标签 java collections

我多次运行以下代码,发现有时我从 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/

相关文章:

java - 如何从 JAVA 应用程序中获取所有 DNS 条目?

java - 区域设置更改后不会调用 OnConfigurationChanged

java - 如何重用使用相同支持迭代器的集合?

c# - 根据2个条件选择使用linq

java - 二维数组列表不会在 eclipse 之外编译

Java Grep 库

java - IntelliJ 中的 SonarQube 本地脚本找不到 mvn(IOException/没有这样的目录)

c# - Collection<T> 与 List<T> 您应该在界面上使用什么?

java - 流数据的理想 Java 数据结构

python - 字典中特定键的总和值