Java ArrayList/String/atomic变量读取线程是否安全?

Jon*_*n M 12 java multithreading synchronization arraylist

我一直在考虑阅读和阅读,但可以找到绝对权威的答案.

我有几个深层数据结构,由包含ArrayLists,Strings和原始值的对象组成.我可以保证这些结构中的数据不会改变(没有线程会对列表进行结构更改,更改引用,更改基元).

我想知道在这些结构中读取数据是否是线程安全的; 即从对象递归读取变量是否安全,迭代ArrayLists等以从多个线程中的结构中提取信息而不同步?

Ami*_*ani 13

它不安全的唯一原因是,如果一个线程正在写入一个字段,而另一个线程同时从该字段读取.没有竞争条件,如果数据没有改变存在.使对象不可变是保证它们是线程安全的一种方法.首先阅读IBM的这篇文章.

  • 不幸的是,这是错误的.在没有*before-before*条件(由语言规范定义)的情况下,"before","while"和"after"之类的词语没有任何意义.使用`final`使对象不可变是一个好主意,所以我不会贬低,但是没有内存障碍可以获得线程安全的想法是非常非常错误的. (2认同)
  • @erickson,公平地说,问题并没有真正解决这个问题.他问多个线程是否可以安全地读取数据,如果数据安全发布(你得到的是什么),他们可以这样做.所以也许"非常非常错"有点强,也许你想说"是的,数据安全发布的时间长". (2认同)

eri*_*son 5

a的成员ArrayList不受任何内存障碍的保护,因此无法保证在线程之间可以看到对它们的更改.即使对列表进行的唯一"更改"是其构造,这也适用.

线程之间共享的任何数据都需要"内存屏障"以确保其可见性.有几种方法可以实现这一目标.

首先,final在构造函数完成后,任何线程都可以看到在构造函数中声明和初始化的任何成员.

对所有声明的成员的更改对volatile所有线程都是可见的.实际上,写入从任何高速缓存"刷新"到主存储器,任何访问主存储器的线程都可以看到它.

现在它变得有点棘手.该线程写入volatile变量之前,线程所做的任何写操作都会被刷新.同样,当一个线程读取一个volatile变量时,它的缓存被清除,随后的读取可能会从主内存重新填充它.

最后,一个synchronized块是象性读写,与原子的附加质量.获取监视器后,将清除线程的读取缓存.释放监视器后,所有写入都将刷新到主存储器.

使这项工作的一种方法是让填充共享数据结构的线程将结果分配给volatile变量(AtomicReference或其他合适的java.util.concurrent对象).当其他线程访问该变量时,它们不仅保证获得该变量的最新值,而且还保证线程在将值赋给变量之前对数据结构所做的任何更改.