1

从书中引用java并发实践:

同步的性能成本来自多个来源。synchronized 和 volatile 提供的可见性保证可能需要使用称为内存屏障的特殊指令,这些指令可以刷新或使缓存无效、刷新硬件写入缓冲区和停止执行管道。内存屏障也可能会产生间接的性能影响,因为它们会抑制其他编译器优化;大多数操作不能用内存屏障重新排序。在评估同步的性能影响时,区分竞争同步和非竞争同步很重要。同步机制针对无竞争的情况进行了优化(volatile 始终是无竞争的),在撰写本文时,对于大多数系统而言,“快速Ͳpath”无竞争同步的性能成本范围为 20 到 250 个时钟周期。

你能更清楚地澄清这一点吗?如果我有大量线程读取 volaile 变量怎么办?

你能提供争用定义吗?

是否有衡量争用的工具?它是在哪些价值观中衡量的?

4

1 回答 1

3

你能更清楚地澄清这一点吗?

那是一个涉及很多话题的密集段落。您具体要求澄清哪个或哪些主题?你的问题太宽泛了,无法令人满意地回答。对不起。

现在,如果您的问题是针对非竞争同步的,这意味着 JVM 中的线程不必阻塞、解除阻塞/通知然后回到阻塞状态。

在底层,JVM 使用硬件特定的内存屏障来确保

  1. 始终从volatile主内存读取和写入字段,而不是从 CPU/核心缓存读取和写入字段,并且
  2. 您的线程不会阻止/解除阻止来访问它。

没有争议。当您使用同步块 OTH 时,您的所有线程都处于阻塞状态,除了一个线程读取同步块保护的任何数据。

让我们调用那个线程,即访问同步数据的线程 A

现在,这里是关键,当线程 A处理完数据并存在同步块时,这会导致 JVM唤醒所有其他正在/正在等待线程 A退出同步块的线程。

他们都醒来了(这在 CPU/内存方面很昂贵)。他们都竞相试图获得同步块。

想象一下一大群人试图通过一个小房间离开拥挤的房间。是的,就像那样,这就是线程在尝试获取同步锁时的行为方式。

但只有一个人得到它并进入。所有其他人都回到睡眠状态,有点像所谓的阻塞状态。这也是昂贵的,资源方面的。

因此,每当其中一个线程存在同步块时,所有其他线程都会发疯(我能想到的最佳心理形象)来访问它,一个得到它,然后所有其他线程都回到阻塞状态。

这就是使同步块变得昂贵的原因。现在,请注意:在 JDK 1.4 之前,它曾经非常昂贵。那是17年前的事了。Java 1.4 开始出现一些改进(2003 IIRC)。

然后 Java 1.5 在 12 年前的 2005 年引入了更大的改进,这使得同步块的成本更低。

记住这些事情很重要。那里有很多过时的信息。

如果我有大量线程读取 volaile 变量怎么办?

就正确性而言,这并不重要。无论线程数如何,字段将volatile始终显示一致的值。

现在,如果您有大量线程,性能可能会因为上下文切换、内存利用率等而受到影响(不一定和/或主要是因为访问volatile字段。

你能提供争用定义吗?

请不要误会,但如果你问这个问题,恐怕你还没有完全准备好使用你正在阅读的那本书。

您将需要对并发和争用进行更基本的介绍。

https://en.wikipedia.org/wiki/Resource_contention

此致。

于 2017-03-06T13:42:30.843 回答