从同步方法调用同步方法的同步开销是多少?
这两者之间的性能有什么区别吗?
synchronized void x() {
y();
}
synchronized void y() {
}
和这个
synchronized void x() {
y();
}
void y() {
}
这两者之间的性能有什么区别吗?
synchronized void x() {
y();
}
synchronized void y() {
}
和这个
synchronized void x() {
y();
}
void y() {
}
是的,除非 JVM 将调用内联到 ,否则会提供额外的性能开销,而现代 JIT 编译器将在相当短的时间内完成此操作。首先,考虑您介绍的在类外可见的情况。在这种情况下,JVM必须在进入时进行检查,以确保它可以进入对象上的监视器;当调用来自 时,此检查将始终成功,但不能跳过,因为调用可能来自类外部的客户端。此额外检查会产生少量费用。y()
y()
y()
x()
此外,请考虑以下情况:。在这种情况下,编译器仍然没有优化同步;请参阅以下对空的拆解:y()
private
y()
private synchronized void y();
flags: ACC_PRIVATE, ACC_SYNCHRONIZED
Code:
stack=0, locals=1, args_size=1
0: return
根据规范对同步
的定义,每个进入块或方法的入口对对象执行锁定操作,离开执行解锁操作。在锁定计数器降至零之前,任何其他线程都无法获取该对象的监视器。据推测,某种静态分析可以证明一个方法只能从其他方法中调用,但是Java的多源文件支持充其量会使它变得脆弱,甚至忽略反射。这意味着 JVM 在输入 y()
时仍必须递增计数器:synchronized
private synchronized
synchronized
在调用方法时监视条目,并在返回时监视退出,由 Java 虚拟机的方法调用和返回指令隐式处理,就像使用了 monitorenter 和 monitorexit 一样。
synchronized
@AmolSonawane正确地注意到,JVM可以通过执行锁粗化(本质上是内联方法)在运行时优化此代码。在这种情况下,在 JVM 决定执行 JIT 优化后,从 x()
到 y()
的调用不会产生任何额外的性能开销,但当然,从任何其他位置直接调用仍需要单独获取监视器。y()
y()
Benchmark Mean Mean error Units
c.a.p.SO18996783.syncOnce 21.003 0.091 nsec/op
c.a.p.SO18996783.syncTwice 20.937 0.108 nsec/op
=>无统计学差异。
查看生成的组件可发现,尽管锁定已同步,但已执行并内联。y_sync
x_sync
完整结果:
Benchmarks:
# Running: com.assylias.performance.SO18996783.syncOnce
Iteration 1 (5000ms in 1 thread): 21.049 nsec/op
Iteration 2 (5000ms in 1 thread): 21.052 nsec/op
Iteration 3 (5000ms in 1 thread): 20.959 nsec/op
Iteration 4 (5000ms in 1 thread): 20.977 nsec/op
Iteration 5 (5000ms in 1 thread): 20.977 nsec/op
Run result "syncOnce": 21.003 ±(95%) 0.055 ±(99%) 0.091 nsec/op
Run statistics "syncOnce": min = 20.959, avg = 21.003, max = 21.052, stdev = 0.044
Run confidence intervals "syncOnce": 95% [20.948, 21.058], 99% [20.912, 21.094]
Benchmarks:
com.assylias.performance.SO18996783.syncTwice
Iteration 1 (5000ms in 1 thread): 21.006 nsec/op
Iteration 2 (5000ms in 1 thread): 20.954 nsec/op
Iteration 3 (5000ms in 1 thread): 20.953 nsec/op
Iteration 4 (5000ms in 1 thread): 20.869 nsec/op
Iteration 5 (5000ms in 1 thread): 20.903 nsec/op
Run result "syncTwice": 20.937 ±(95%) 0.065 ±(99%) 0.108 nsec/op
Run statistics "syncTwice": min = 20.869, avg = 20.937, max = 21.006, stdev = 0.052
Run confidence intervals "syncTwice": 95% [20.872, 21.002], 99% [20.829, 21.045]