如下面的示例所示,一旦在call
方法中对某个对象进行了锁定,就不需要其他方法来使用synchronized关键字。
public class Prac
{
public static void main(String[] args)
{
new Prac().call();
}
private synchronized void call()
{
further();
}
private synchronized void further()
{
oneMore();
}
private synchronized void oneMore()
{
// do something
}
}
但是,如果我仍然将synchronized
关键字添加到further
和onceMore
,那么效果会如何影响?或者根本不受影响?
编辑:如果需要锁定或锁定,是否会增加检查成本(遇到synchronized关键字后)?这种检查在内部是否增加了开销?
编辑:应用程序不会只有一个线程,这里的代码只是示例代码。可以用run方法替换main
答案 0 :(得分:3)
表现不会受到影响。获得已经获得的锁只会带来任何成本。这种技术称为biased locking。默认情况下,启用偏置锁定。这就是为什么单线程应用程序不会受到调用synchronized方法的影响。
Java SE 6 Performance White Paper:
对象是"有偏见"通过monitorenter字节码或同步方法调用首先获取其监视器的线程;后续的监视器相关操作可以由该线程执行,而不使用原子操作,从而产生更好的性能,特别是在多处理器机器上。
答案 1 :(得分:3)
同步机制使方法稍慢,如果只有一个线程,请尝试不同步方法
答案 2 :(得分:2)
由于JDK 7 HotSpot JVM能够通过消除嵌套锁来优化此类代码。
优化名为-XX:+EliminateNestedLocks
,默认情况下处于启用状态。
在JIT编译期间删除了冗余锁,因此即使检查锁是否已被占用,也没有运行时开销。但是,此优化仅在监视对象为static final
或锁定this
对象时才有效。
答案 3 :(得分:0)
我根据下面的评论修改了基准。
在这个基准测试中,多次获取锁定,偶尔花费的时间比acquire_once少,但我认为这是因为背景线程如gc和jit
public class Benchmark {
final int count = 10000;
boolean the_bool = false; // prevent no-op optimization inside the loop
public static void main(String[] args) {
Benchmark benchmark = new Benchmark();
benchmark.start();
}
public void start() {
//run the test 12000 times
for (int i = 0; i < 12000; i++) {
long start = System.nanoTime();
aqcuire_lock_multiple_times();
long end = System.nanoTime();
long time1 = end - start; // time to acquire lock multiple times
start = System.nanoTime();
acquire_lock_once();
end = System.nanoTime();
long time2 = end - start; // the time to acquire lock once
if (time1 <= time2) {
String m = MessageFormat.format(
"time1:{0}ns < time2:{1}ns, iteration:{2}", time1, time2, i);
System.out.println(m);
}else{
// acquire the lock once is faster as expected
}
}
}
public synchronized void aqcuire_lock_multiple_times() {
for (int i = 0; i < count; i++) {
synchronized (this) {
the_bool = !the_bool;
}
}
}
public synchronized void acquire_lock_once() {
for (int i = 0; i < count; i++) {
the_bool = !the_bool;
}
}
}
这里我用jdk1.7编译它(与eclipse编译器的结果是一样的)
所以我的结论是有开销。