java - 同步块(synchronized block)是否会导致所有写缓存刷新?

标签 java multithreading synchronization jls

我对synchronized如何工作以及如何/何时从本地缓存刷新写入感兴趣。让我们假设我有以下代码:

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);
  }
}

我有几个问题:

  1. 所有三个示例是否共享相同的“线程安全”级别(考虑到诸如第一次写入由一个线程完成、第二次写入在第一个写入(是吗?)之后由另一个线程完成等细节),即“是吗?”保证打印出 5010”?
  2. 在同步块(synchronized block)之外“操作”或使用非 volatile 属性是否存在性能差异(至少理论上)(我希望 volatile 访问会慢如 this post confirms ),但在同步块(synchronized block)的情况下是“冲水”价格仅在跨越同步开始/结束时支付,或者在 block 内也有差异?

最佳答案

I am interested in how synchronized works in sense how/when it flushes writes from local caches.

实际上,synchronized 不会刷新本地缓存中的写入操作。它只是表现得好像确实如此。

Does all three examples share same "thread-safety" level (taking into account specifics like first write is done by one thread and second write is done after first one (is it?) and by another thread) i.e. "is it guaranteed that 10 is printed"?

它们都提供略有不同形式的线程安全。如果其他线程同时访问该对象,那么它们都不是真正安全的。例如,访问 counter 的另一个线程必须同时持有 String.classInteger.class 锁,以确保它不会在操作期间查看计数器。第三个使用非原子的增量操作,尽管如果没有其他线程尝试修改 counter,那么它是安全的。

Is there performance difference (at least theoretical) in "operating" outside a synchronized block or working with non-volatile properties (I would expect volatile access to be slower as this post confirms) but in case of synchronized block is the "flushing" price paid only when crossing synchronized start/end or is there also difference while inside the block?

没有区别。进入同步块(synchronized block)是有成本的,因为必须获取锁并且必须在入口点禁用一些优化。退出区 block 也有类似的成本。

在 block 内,没有任何成本,因为安全性是由程序员提供的,确保他们不允许任何线程修改对象,除非它持有相同的锁,并且没有两个线程可以同时持有相同的锁。一般来说,代码甚至可能不知道它是否位于一个或多个同步 block 内,因为它可能位于调用树的深处。

关于java - 同步块(synchronized block)是否会导致所有写缓存刷新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56639195/

相关文章:

java - 在 Android 中检索 SharedPreferences

amazon-web-services - 使用 AWS s3 同步备份符号链接(symbolic link)

java - 使用 Jython 从 Java 代码调用 Python 导致错误 : ImportError: no module named nltk

java - 我如何检测 JasperViewer 处理报告时间

java - 我需要在同步方法中调用 wait() 和 notify() 吗?

java - display.async 和平滑过渡

java - 如何保护一种方法免受不同请求的影响

c# - thread worker 内部线程安全

java - 通知 postgres 对 java 应用程序的更改

java - IActionDelegate 的 selectionChanged() 未被调用