基元数组写入的 Java 并发可见性
我最近在我的代码库中发现了这个宝石:
/** This class is used to "publish" changes to a non-volatile variable.
*
* Access to non-volatile and volatile variables cannot be reordered,
* so if you make changes to a non-volatile variable before calling publish,
* they are guaranteed to be visible to a thread which calls syncChanges
*
*/
private static class Publisher {
//This variable may not look like it's doing anything, but it really is.
//See the documentaion for this class.
private volatile AtomicInteger sync = new AtomicInteger(0);
void publish() {
sync.incrementAndGet();
}
/**
*
* @return the return value of this function has no meaning.
* You should not make *any* assumptions about it.
*/
int syncChanges() {
return sync.get();
}
}
这是这样使用的:
线程 1
float[][] matrix;
matrix[x][y] = n;
publisher.publish();
线程 2
publisher.syncChanges();
myVar = matrix[x][y];
线程 1 是连续运行的后台更新线程。线程 2 是一个 HTTP 工作线程,它不关心它读取的内容是否以任何方式一致或原子,只关心写入“最终”到达那里,并且不会丢失为并发神。
现在,这触发了我所有的警钟。在不相关代码深处编写的自定义并发算法。
不幸的是,修复代码并非易事。Java 对并发基元矩阵的支持并不好。看起来解决这个问题的最清晰方法是使用 ,但这可能会对性能产生负面影响。显然,正确性更重要,但似乎我应该在将其从性能敏感区域中剥离出来之前证明这是不正确的。ReadWriteLock
根据 java.util.concurrent 文档,以下创建关系:happens-before
线程中的每个操作都发生在该线程中的每个操作之前,这些操作在程序顺序的后面出现。
对易失性字段的写入发生在每次后续读取该字段之前。易失性字段的写入和读取与进入和退出监视器具有相似的内存一致性效果,但不需要互斥锁定。
所以听起来像这样:
- 矩阵写入发生之前发布() (规则 1)
- publish() 发生在同步之前更改() (规则 2)
- syncChanges() 发生在矩阵读取之前(规则 1)
因此,代码确实为矩阵建立了一个先发生之前链。
但我不相信。并发性很难,我不是领域专家。我错过了什么?这确实安全吗?