多个同步对象的开销

时间:2018-11-15 16:23:07

标签: java synchronized

考虑以下代码:

void A() {
    synchronized (obj) {
        for (int i = 0; i < 1000; i++) {
            B();
        }
    }
}

void B() {
    synchronized (obj) {
        // Do something
    }
}

在调用A时“同步”的开销是多少?会接近只有一个“同步”的开销吗?

2 个答案:

答案 0 :(得分:1)

这个(合法)问题的答案取决于操作系统,硬件和特定的VM实施。

不考虑函数调用的开销,在一个OS /体系结构上(考虑现代处理器/ OS / VM),可能几乎不花钱,而在另一个OS /体系结构上(考虑纯粹的软件处理器仿真),它的花费可能更多。在单个绿色线程VM上,它的成本可能接近于零(调用开销除外)。即使在具有同等性能的ARM和Intel之间,成本也会有所不同。

synchronized()通常是通过使用OS同步原语在VM内部实现的,并使用一些试探法来加速常见情况。操作系统依次使用硬件指令和启发式方法执行此任务。通常,随后获取已经获取的同步原语在OS中非常有效,而在典型的生产级VM上非常高效。

通常,在现代的Windows / Linux VM和Intel / AMD处理器上,它不需要花费很多CPU周期(假设闲置的机器是闲置的),并且在低纳秒范围内。

注意,通常,这是一个非常复杂的主题。涉及多层软件,硬件(以及在相同硬件资源上运行的其他任务的影响)。对此处很小的一个子主题的严格研究都可以组成多个博士学位。论文。

但是,在实践中,我的建议是假设在小循环中每秒同步的成本为零,除非您遇到特定的瓶颈(这不太可能发生)。

如果存在大量迭代,则与单次同步相比,无疑会增加成本,并且总体效果取决于您在循环内所做的工作。通常,每次迭代都需要做一些工作,使得相对开销可以忽略不计。但是在某些情况下,它可能会阻止循环优化并增加大量开销(与单次同步相比可观,而不是实际的措施)。但是,在常见的大循环实际情况下,应该考虑不同的设计,并避免执行外部同步以减少lock contention

要了解VM的实现,您可以查看this paper的“同步”部分。这有点过时,但很容易理解。

答案 1 :(得分:0)

synchronized锁是可重入的,并且在线程已经持有锁的情况下获得锁是:a)检查它是否已经锁住的时间,b)递增计数器并随后递减的时间

第一个耗时最长,每次加约10-50 ns。