多级Java同步
如下面的示例所示,一旦在多级Java同步,java,performance,synchronization,Java,Performance,Synchronization,如下面的示例所示,一旦在call方法中锁定了一个对象,就不需要进一步的方法具有synchronized关键字 public class Prac { public static void main(String[] args) { new Prac().call(); } private synchronized void call() { further(); } private synchronized v
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
,性能会受到怎样的影响?还是根本不受影响
编辑:如果有锁或需要锁,是否会增加检查成本(遇到同步关键字后)?在内部,这种检查会增加开销吗
编辑:应用程序不会只有一个线程,这里的代码只是示例代码。可以用run方法替换main性能不会受到影响。获取一个已经获取的锁不需要任何成本。这种技术被称为。默认情况下,启用偏置锁定。这就是为什么调用同步方法不会影响单线程应用程序 : 对象“偏向”于首先通过monitorenter字节码或同步方法调用获取其监视器的线程;后续的监视器相关操作可以由该线程执行,而无需使用原子操作,从而获得更好的性能,特别是在多处理器机器上
同步机制会使方法稍微慢一点,因此如果只有一个线程,请尝试不同步方法我根据下面的注释修改了基准。
在此基准中,多次获取锁,有时比一次获取锁花费的时间更少,但我认为这是因为像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;
}
}
}
公共类基准{
最终整数计数=10000;
boolean the_bool=false;//防止循环内无操作优化
公共静态void main(字符串[]args){
基准=新基准();
benchmark.start();
}
公开作废开始(){
//运行测试12000次
对于(int i=0;i<12000;i++){
长启动=System.nanoTime();
aqcuire_lock_多次();
long end=System.nanoTime();
long-time1=end-start;//多次获取锁的时间
start=System.nanoTime();
获取_lock_once();
end=System.nanoTime();
long-time2=end-start;//获取锁一次的时间
如果(time1,因为JDK 7 HotSpot JVM能够通过消除嵌套锁来优化这些代码
该优化称为-XX:+EliminatenestLocks
,默认情况下处于启用状态
在JIT编译期间,冗余锁被删除,因此即使检查锁是否已被占用,也不会产生运行时开销。但是,只有当监视对象是static final
或锁定this
对象时,此优化才有效。不会出现任何此类性能问题。但是,只有当您ant直接调用其他方法。应用程序的可能副本不会只有一个线程,这里的代码只是示例代码。可能会将main替换为run方法。因此,我们必须对不希望并行处理的每个方法使用synchronized。对象是“有偏差的”对于首先通过monitorenter字节码或同步方法调用获取其监视器的线程,该线程可以执行后续的监视器相关操作,而无需使用原子操作,从而获得更好的性能,特别是在多处理器机器上,锁定除向w对象“有偏差”将导致一个相对昂贵的操作,从而取消偏差。消除原子操作的好处必须超过取消的惩罚,此优化才能有利可图。对象“有偏差”的线程之外的线程的锁定尝试将导致一个相对昂贵的操作
这可能会导致问题,不确定是否需要偏置锁定?分析表明,大多数应用程序的大部分时间锁都是由同一线程获取的。如果您的情况不是这样,您可以禁用偏置锁定或在这样的特定位置使用ReentrantLock。它不会不要使用有偏锁定。你把有偏锁和递归锁混淆了。最初的问题是关于递归锁。HotSpot JVM有默认启用的-XX:+EliminatedLocks
优化,无论-XX:+UseBiasedLock
启用与否,也不管程序是单线程还是不是。你的基准不正确。