【发布时间】:2019-06-17 21:35:55
【问题描述】:
我对@987654323@ 如何/何时从本地缓存刷新写入感兴趣。假设我有以下代码:
class Scratch1 {
int counter = 0;
Scratch1() throws ExecutionException, InterruptedException {
counter += 5;
counter += 5;
// Does this cause to flush possibly cached value written by main thread even if it locks
// on totally unrelated object and the write doesnt happen inside the sync block?
synchronized (String.class) {}
Executors.newCachedThreadPool().submit(() -> {
for (int i = 0; i < 1000; i++) {
counter += 5;
}
synchronized (Integer.class) {}
}).get();
System.out.println(counter);
}
}
class Scratch2 {
int counter = 0;
Scratch2() throws ExecutionException, InterruptedException {
// Or is this only possible working way how flush written data.
synchronized (String.class) {
counter += 5;
counter += 5;
}
Executors.newCachedThreadPool().submit(() -> {
synchronized (Integer.class) {
for (int i = 0; i < 1000; i++) {
counter += 5;
}
}
}).get();
System.out.println(counter);
}
}
class Scratch3 {
volatile int counter = 0;
Scratch3() throws ExecutionException, InterruptedException {
counter += 5;
counter += 5;
Executors.newCachedThreadPool().submit(() -> {
for (int i = 0; i < 1000; i++) {
counter += 5;
}
}).get();
System.out.println(counter);
}
}
我有几个问题:
- 所有三个示例是否共享相同的“线程安全”级别(考虑到第一次写入由一个线程完成,第二次写入在第一个(是吗?)和另一个线程之后完成)即“是保证打印 5010”?
- 在同步块之外“操作”或使用非易失性属性时是否存在性能差异(至少理论上)(我预计易失性访问会像this post confirms 一样慢)但在同步块的情况下是“刷新”的价格仅在跨越同步开始/结束时支付,还是在块内也有差异?
【问题讨论】:
-
Java 语言规范 (JLS) 中没有“缓存”。缓存是一个实现细节。 JLS 的“Memory Model”部分详细解释了当您的线程共享数据时您应该期待什么。您可以从中得出的一条经验法则是;线程 A 在离开
synchronized块之前所做的任何事情都保证在线程 B 进入同一对象上的synchronized块时对线程 B 可见。
标签: java multithreading synchronization jls