在同一对象上同步两次

时间:2015-05-15 17:34:31

标签: java synchronization thread-safety

我正在编写一个实用程序类来实现秒表的行为。这个类的一个重要特性是它被设计为线程安全的。我使用名为private final的{​​{1}}字段进行同步。该类中的两个方法称为lockreset,它们分别重置秒表并启动它。它们实现为:

start

最近,我想到了一个名为public void reset() { synchronized (lock) { beginTime = 0; lapIndex = 0; } } public void start() { synchronized (lock) { if (beginTime == 0) { beginTime = System.nanoTime(); laps[lapIndex++] = beginTime; } } } 的额外便利方法,它会重置并启动秒表。我希望它的行为类似于原子操作,所以我的想法是将其实现为:

restart

但是,public void restart() { synchronized(lock) { reset(); start(); } } reset方法已在start上同步,因此调用lock会在同一对象上同步两次。可能会出现任何问题吗?是否多次同步同一对象的行为定义明确?有必要吗?我已经运行了代码,因为似乎工作正常,但我担心我可能会遗漏一些微线程,这与多线程一样。

2 个答案:

答案 0 :(得分:3)

两次同步没问题。该线程已经拥有了监视器,因此额外的同步并没有真正做多少。这是必要的,否则您的restart()方法可能会被调用reset()start()之间的另一个线程中断。

避免双重同步的一种方法是让restart()reset()start()同步,然后委托给非同步的内部方法。

public void reset() {
    synchronized (lock) {
        _reset();
    }
}

public void start() {
    synchronized (lock) {
        _start();
    }
}

public void restart() {
    synchronized(lock) {
        _reset();
        _start();
    }
}

private void _reset() {
    beginTime = 0;
    lapIndex = 0;
}

private void _start() {
    if (beginTime == 0) {
        beginTime = System.nanoTime();
        laps[lapIndex++] = beginTime;
    }
}

答案 1 :(得分:2)

来自Java语言规范的section 14.19 on synchronized statements

  

synchronized语句获取的锁与通过synchronized方法隐式获取的锁相同(第8.4.3.6节)。 单个帖子可能会多次获得锁定。

同样来自JLS:

  

线程 t 可能会多次锁定特定的监视器;每次解锁都会逆转一次锁定操作的效果。

因此,这应该不是问题。