Java ArrayList能否在多线程环境中用于只读目的?

Java ArrayList能否在多线程环境中用于只读目的?,java,multithreading,arraylist,Java,Multithreading,Arraylist,我有几个ArrayList包含用户定义的对象(例如List,List)。这些对象本质上是不变的,即不提供任何setter,而且,由于问题的性质,“没有人”会试图修改这些对象。填充“ArrayList”后,不允许/不可能进一步添加/删除对象。所以列表不会动态变化 在这种给定条件下,多个线程(同时)能否安全地使用此数据结构(即ArraList)?每个线程只读取对象属性,但不可能执行“设置”操作 所以,我的问题是我可以依赖于ArrayList?如果没有,在这种情况下还可以使用哪些成本较低的数据结构?是

我有几个
ArrayList
包含用户定义的对象(例如
List,List
)。这些对象本质上是不变的,即不提供任何setter,而且,由于问题的性质,“没有人”会试图修改这些对象。填充“ArrayList”后,不允许/不可能进一步添加/删除对象。所以列表不会动态变化

在这种给定条件下,多个线程(同时)能否安全地使用此数据结构(即
ArraList
)?每个线程只读取对象属性,但不可能执行“设置”操作


所以,我的问题是我可以依赖于
ArrayList
?如果没有,在这种情况下还可以使用哪些成本较低的数据结构?

是的,您应该能够将数组传递到每个线程中。只要在任何线程可能获取信息之前完成对数组的写入,就不应该存在访问错误。

如果在安全发布后从未修改过任何对象或数据结构,则可以在线程之间共享它们。如注释中所述,初始化
ArrayList
的写操作与其他线程获取引用的读操作之间必须存在*发生在*之前*的关系

例如,如果在启动其他线程之前或在将列表上的任务提交给
执行器服务之前,完全设置了
阵列列表
,则您是安全的

如果线程已在运行,则必须使用其中一种线程安全机制将
ArrayList
引用移交给其他线程,例如,将其置于
阻塞队列上

即使是最简单的形式,如将引用存储到
静态final
volatile
字段中,也可以使用

请记住,以后永远不要修改对象的前提条件必须始终保持不变。建议通过使用包装列表来强制执行该约束,并在发布之前忘记原始列表引用:

class Example {
  public static final List<String> THREAD_SAFE_LIST;
  static {
    ArrayList<String> list=new ArrayList<>();
    // do the setup
    THREAD_SAFE_LIST=Collections.unmodifiableList(list);
  }
}
类示例{
公共静态最终列表线程安全列表;
静止的{
ArrayList=新建ArrayList();
//进行设置
线程安全列表=集合。不可修改列表(列表);
}
}

类示例{
公共静态最终列表线程安全列表
=Collections.unmodifiableList(Arrays.asList(“foo”、“bar”));
}

如果对象不可能从不同线程更改其状态,那么会出现什么问题?也许我看错了这个问题,但这似乎是一个不需要动脑筋的问题。唯一的问题可能是任何ArrayList元素的状态是否可以更改。我不会将列表传递给其他对象,但可以是列表的深度副本,也可以是完全封装和保护列表的类的对象。是的,您可以。尝试一下。您可能仍然需要某种同步,以确保初始化列表的写操作在读取之前发生,而“之前发生”指的是,或者您可能会遇到缓存一致性或指令重新排序问题,从而导致其他线程看到部分构造的列表。
class Example {
  public static final List<String> THREAD_SAFE_LIST
    =Collections.unmodifiableList(Arrays.asList("foo", "bar"));
}