【问题标题】:Can ArrayList be used for readonly purpose in multithreaded environment?ArrayList 可以在多线程环境中用于只读目的吗?
【发布时间】:2014-03-10 00:12:06
【问题描述】:

我很少有 ArrayList<T> 包含用户定义的对象(例如 List<Student>, List<Teachers>)。这些对象本质上是不可变的,即没有提供设置器 - 而且,由于问题的性质,“没有人”会尝试修改这些对象。一旦填充了“ArrayList”,就不允许/可能进一步添加/删除对象。所以 List 不会动态变化。

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

所以,我的问题是我可以依靠ArrayList 吗?如果没有,在这种情况下可以使用哪些其他更便宜的数据结构?

【问题讨论】:

  • 如果对象不可能从不同的线程改变其状态,那么可能是什么问题?也许我读错了这个问题,但这似乎是一个明智的选择。唯一的问题可能是任何 ArrayList 元素的状态是否可以更改。我不会将列表传递给其他对象,而是将列表的深层副本或完全封装和保护列表的类的对象。
  • 是的,你可以。试试看。
  • 您可能仍需要某种同步来确保初始化列表的写入 happen-before 读取,其中 happen-beforeconcept defined in the JLS,否则您可能会遇到缓存一致性或指令重新排序问题,导致其他线程看到列表部分构建。

标签: java multithreading arraylist


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    例如如果您在启动其他线程之前或在将列表上的任务提交给ExecutorService之前完全设置ArrayList,那么您是安全的。

    如果线程已经在运行,您必须使用其中一种线程安全机制将 ArrayList 引用移交给其他线程,例如把它放在BlockingQueue上。

    即使是最简单的形式,例如将引用存储到 static finalvolatile 字段中也可以使用。

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

    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);
      }
    }
    

    class Example {
      public static final List<String> THREAD_SAFE_LIST
        =Collections.unmodifiableList(Arrays.asList("foo", "bar"));
    }
    

    【讨论】:

      猜你喜欢
      • 2015-10-28
      • 1970-01-01
      • 1970-01-01
      • 2017-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多