繁体   English   中英

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

[英]Is Java ArrayList / String / atomic variable reading thread safe?

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

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

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

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

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

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

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

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

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

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

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

如果数据在创建之后永远不会被修改,那么你应该没问题,读取将是线程安全的。

为了安全起见,您可以使所有数据成员“最终”并使所有访问函数尽可能重入; 这可以确保线程安全,并且如果您将来更改它,可以帮助保持代码线程安全。

一般而言,尽可能多的成员“最终”有助于减少错误的引入,因此许多人提倡将其作为Java最佳实践。

正如对其他人的答案的补充:如果您确定需要同步数组列表,可以调用Collections.synchronizedList(myList),它将返回一个线程安全的实现。

我看不出如何使用多个线程从ArrayLists,Strings和原始值读取应该是什么问题。

只要您只是阅读,就不需要同步。 对于字符串和原语,它肯定是安全的,因为它们是不可变的。 对于ArrayLists,它应该是安全的,但我没有权威。

不要使用java.util.Vector ,使用java.util.Collections.unmodifiableXXX()的包装,如果他们真的是不可修改的,这将保证他们不会改变,并且会强制执行合同。 如果要修改它们,则使用java.util.Collections.syncronizedXXX() 但这只能保证内部线程安全。 使变量final也将有助于编译器/ JIT进行优化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM