如果线程在安全出版物之后从未修改过,则可以共享线程之间的任何对象或数据结构。如注释中所述,在初始化ArrayList
的写入和其他线程获取引用的读取之间必须存在* happen-before *关系。
E.g.如果在启动其他线程之前或在将列表中的任务提交到ExecutorService
之前完全设置了ArrayList
,则表明您是安全的。
如果线程已经运行,则必须使用其中一个线程安全机制将ArrayList
引用移交给其他线程,例如,通过把它放在BlockingQueue
。
即使是最简单的形式,如将参考文件存储到static final
或volatile
字段也可以使用。
请记住,以后不要修改对象的前提条件必须始终成立。我们建议使用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"));
}
如果对象不可能有来自不同线程的状态变化,那么问题是什么?也许我读错了这个问题,但它似乎是一个明智之举。唯一的问题可能是如果任何ArrayList元素的状态可以改变。我不会将列表传递给其他对象,而是将列表的深层副本或类的对象完全封装并保护列表。 –
是的,你可以。尝试一下。 –
您可能仍然需要某种同步来确保初始化列表的写操作发生在读操作之前,其中*发生之前*指的是[JLS中定义的概念](http://docs.oracle.com)。 com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5),否则可能会遇到缓存一致性或指令重新排序的问题,导致其他线程看到部分构建的列表。 – user2357112