注意::这个问题与内存可见性有关,而不是“公共”,“私人”等。
假设我有以下课程:
public class Data {
public final byte[] array;
public final int offset, length;
public Data(byte[] array, int offset, int length) {...}
...
}
(上述数组中的元素可以通过未显示的方法进行更改。)
现在假设我在另一个类中有一个包含给定数据的队列:
final ConcurrentLinkedQueue<Data> queue = new ConcurrentLinkedQueue<>();
现在假设我在队列中有以下代码:
Data data = queue.poll();
... code for reading the elements in the data object.
我的问题是:在轮询队列之前设置的数组中的元素是否保证对从队列中轮询数据的线程可见?
据我所知,队列轮询后设置的元素对读者不可见,我只对轮询队列前设置的元素感兴趣。
如果没有,我的理解是在调用poll方法之后放入以下代码将确保数组的可见性
data = new Data(data.array, data.offset, data.length);
因为对象构造可确保对象字段的完全可见性。这是对的吗?
谢谢!
答案 0 :(得分:4)
java.util.concurrent及其子包中所有类的方法将这些保证扩展到更高级别的同步。特别是:
在将对象放入任何并发集合之前的线程中的操作发生在从另一个线程中的集合访问或删除该元素之后的操作之前。
所以是的,您可以保证在将对象存储到队列之前看到数组中已经设置的值。 (我假设在这里将te数组存储到队列中之后你不会修改te数组。)
答案 1 :(得分:1)
在对象构建之后,保证最终字段可见且正确。注意:这不会扩展到这些字段引用的对象。即byte []可能不一致(但我怀疑它将在大多数JVM上)
有一个简单的解决方案是使用ExecutorService。它不仅包装了一个队列和一个线程池,而且对volatile字段进行了足够的访问,以确保您的数据正确无误。
简而言之,保持简单,使用标准库,它更有可能发挥作用。