contains方法的java.util.List是线程安全的吗?

contains方法的java.util.List是线程安全的吗?,java,multithreading,arraylist,Java,Multithreading,Arraylist,我将java.util.List声明如下: private static List<String> extensions = null; 私有静态列表扩展=null; 它总是由单个线程填充 但是多个线程可以同时调用扩展上的方法包含(E) 它是线程安全的吗?否,默认情况下,列表不是线程安全的。 如果你想让它线程安全。使用集合。synchronizedList()。否,默认情况下,列表不是线程安全的。 如果你想让它线程安全。使用集合.synchronizedList()。 列表在启动

我将java.util.List声明如下:

private static List<String> extensions = null;
私有静态列表扩展=null;
它总是由单个线程填充

但是多个线程可以同时调用
扩展
上的方法
包含(E)


它是线程安全的吗?

否,默认情况下,列表不是线程安全的。
如果你想让它线程安全。使用集合。synchronizedList()。

否,默认情况下,列表不是线程安全的。 如果你想让它线程安全。使用集合.synchronizedList()。

列表在启动时由单个线程填充,以后无法修改。现在包含线程安全吗

如果您正在谈论一个
ArrayList
,如标签所示,那么是的。谈论
List
的线程安全是没有意义的,因为接口没有实现

查看arraylist的实现(),您可以看到它只读取共享状态,但不写入任何内容

但要小心:

  • 您的字段类型为
    List
    。您能否保证存储在该字段中的变量的运行时类型始终为
    ArrayList
  • 更重要的问题是:文档是否说该方法是线程安全的?否则,Java的未来版本可能会使它变得不安全,这不会被认为是一个破坏性的改变

  • 如果一个线程正在插入数据,而另一个线程正在调用
    Contains
    ,那么这将不是线程安全的。考虑<代码>添加< /代码>的实现:

    public void add(int index, E element) {
         rangeCheckForAdd(index);
    
         ensureCapacity(size+1);  // Increments modCount!!
         System.arraycopy(elementData, index, elementData, index + 1,
                          size - index);
         elementData[index] = element;
         size++;
    }
    
    假设您有一个包含4个元素的列表,其内部数组的容量为6。内部数组看起来像这样
    {a,b,c,d,null,null}
    ,私有字段
    大小将设置为4,以限定列表的边界

    如果我现在在位置2插入
    x
    ,将会发生以下情况:

  • arraycopy
    c
    d
    向右移动,就像
    {a,b,c,c,d,null}
  • 下一行将插入
    x
    {a,b,x,c,d,null}
  • 下一行将
    size
    增加到5,更新列表的边界
  • 注意,如果在步骤1和步骤3之间调用列表中的
    Contains(d)
    ,将返回
    false
    。这是因为
    size
    仍然设置为4,并且列表似乎包含
    {a,b,c,c}
    ,而
    {d,null}
    将被忽略

    列表在启动时由单个线程填充,以后无法修改。现在包含线程安全吗

    如果您正在谈论一个
    ArrayList
    ,如标签所示,那么是的。谈论
    List
    的线程安全是没有意义的,因为接口没有实现

    查看arraylist的实现(),您可以看到它只读取共享状态,但不写入任何内容

    但要小心:

  • 您的字段类型为
    List
    。您能否保证存储在该字段中的变量的运行时类型始终为
    ArrayList
  • 更重要的问题是:文档是否说该方法是线程安全的?否则,Java的未来版本可能会使它变得不安全,这不会被认为是一个破坏性的改变

  • 如果一个线程正在插入数据,而另一个线程正在调用
    Contains
    ,那么这将不是线程安全的。考虑<代码>添加< /代码>的实现:

    public void add(int index, E element) {
         rangeCheckForAdd(index);
    
         ensureCapacity(size+1);  // Increments modCount!!
         System.arraycopy(elementData, index, elementData, index + 1,
                          size - index);
         elementData[index] = element;
         size++;
    }
    
    假设您有一个包含4个元素的列表,其内部数组的容量为6。内部数组看起来像这样
    {a,b,c,d,null,null}
    ,私有字段
    大小将设置为4,以限定列表的边界

    如果我现在在位置2插入
    x
    ,将会发生以下情况:

  • arraycopy
    c
    d
    向右移动,就像
    {a,b,c,c,d,null}
  • 下一行将插入
    x
    {a,b,x,c,d,null}
  • 下一行将
    size
    增加到5,更新列表的边界
  • 注意,如果在步骤1和步骤3之间调用列表中的
    Contains(d)
    ,将返回
    false
    。这是因为
    size
    仍然设置为4,并且列表似乎包含
    {a,b,c,c}
    ,而
    {d,null}
    将被忽略

    列表在启动时由单个线程填充,以后无法修改。现在包含线程安全吗

    以这种方式使用的对象称为“有效不可变”——程序可以更改对象,但不能更改。Brian Goetz的书《Java并发实践》中有一节专门讨论有效不可变对象的安全发布

    简单的回答(假设我记得正确)是,如果在构造函数中填充列表,并且在构造函数返回之前没有其他线程可以访问该列表,那么该列表将安全发布。当然,我假设你放在列表中的项目实际上也是不变的

    “安全发布”意味着其他线程将保证在其预期的最终状态下查看列表。如果列表未安全发布,则在不同处理器上运行的线程可能会看到不同版本的列表(可能包括列表处于不一致状态的某些版本,当您尝试访问它时,可能会使程序崩溃)

    列表在启动时由单个线程填充,以后无法修改。现在包含线程安全吗

    以这种方式使用的对象称为“有效不可变”——程序可以更改对象,但不能更改。Brian Goetz的书《Java并发实践》中有一节专门讨论安全pu