使用 synchronized 时寄存器刷新如何工作?

How does register flushing work when synchronized is used?

我从《Java 性能》一书中读到,发现以下代码在具有许多寄存器的机器上 运行 花费了惊人的时间:

Vector v = initVector();
    for (int i = 0; i < v.size(); i++) {
        process(v.get(i));
    }

因为 Vector class 的 get() 和 size() 方法是同步的,事实证明所有这些调用所需的寄存器刷新(到主内存)是一个巨大的性能问题.

避免这种情况的一种方法是将大量连续的、细粒度的同步调用包装在一个同步块中,如下所示:

Vector v = initVector();
    synchronized (v) {
        for (int i = 0; i < v.size(); i++) {
            process(v.get(i));
        }
    }

我有以下问题:

  1. 为什么即使 size() 和 get() 方法不更改寄存器中变量的值,寄存器刷新也很昂贵?在我看来,没有什么可以刷新回主内存的。我错了吗?
  2. 作者建议的解决方案是否意味着一旦几个内部连续的同步方法被包裹在一个外部同步调用中,内部的不再进行寄存器刷新,并且只有一个最终寄存器刷新在外层?

谢谢!

  1. 只读方法仍然需要获取锁,否则另一个线程可以在您读取时进行更改,从而导致随机行为。

  2. 作者建议的解决方案只获取一次锁,在循环开始之前,并在循环结束时释放它。这样,如果您必须在循环的每一步都获取锁,您将跳过许多 lock/release 循环。