共享资源可以安全地用作同步块的锁吗?

时间:2010-07-09 17:05:52

标签: java synchronization locking

我经常发现自己的代码是

private static final MyType sharedResource = MyType();
private static final Object lock = new Object();
...
synchronized(lock)
{
    //do stuff with sharedResource
}

这是非常必要的还是可以将sharedResource用作锁本身,如

private static final MyType sharedResource = MyType();
...
synchronized(sharedResource)
{
    //do stuff with sharedResource
}

注意:示例中显示的同步块将存在于正在执行工作的方法中,而不是方法本身或同步方法。

编辑:在一些答案中已经指出了一个非常好的观点,即如果我们处理多个共享资源,那么第一个“对象”技术会更安全。

警告 sharedResource为static这一事实非常重要!如果是static,则this上锁定的同步方法或同步块将不起作用。锁定对象也必须是static

5 个答案:

答案 0 :(得分:1)

我看到的唯一问题是,如果sharedResource将方法定义为MyType,则使用synchronized作为锁。在这种情况下,我发生了一些奇怪的行为,MyType的开发人员并不打算这样做。 (有关示例,请参阅glowcoder的评论。)

否则它应该没问题,但是如果你只需要一个锁,那么只需在this上同步而不是引入一个额外的虚拟对象。

是的,你是否真的让你的lock对象变得静止?因为这意味着所有实例都锁定在同一个监视器上,即它们可以相互阻塞,这可能不是您想要的行为。

答案 1 :(得分:1)

两者的利弊

第一个选项优点:允许锁定概念,而不是对象。如果你必须为一个动作锁定多个资源(通常不建议,但有时需要),你可以更少担心竞争条件。

缺点:仍然可以修改对象,因此您需要确保对对象的访问仅限于遵守外部锁定的方法。

第二个选项优点:锁定对象应该阻止其他人修改它(尽管你应该仔细检查确切的语法。)编辑:与上面相同的con - 如果方法在内部不是synchronized,你仍然可能遇到不遵守合同的方法。

缺点:您阻止访问所有方法,即使那些与您尝试操作的方法无关的方法,这可能会导致速度减慢并可能导致死锁。然而,你可以很容易地证明这种情况,如果是这种情况你的对象做了太多的工作,应该分解。

编辑:请允许我在这里澄清第2部分(将MyType分解为MyFoo和MyBar的案例可供辩论......)

class MyType {
   Foo foo;
   Bar bar;

   void doFoo() { foo.do(); }
   void doBar() { bar.do(); }
}

class MyActions {
    MyType thing;

    void lotsOfFoo() {
        // blocks bar :-(
        synchronized(thing) { thing.doFoo(); } 
    }

    void lotsOfBar() {
        // blocks foo :-(
        synchronized(thing) { thing.doBar(); } 
    }

}

就个人而言,我更频繁地使用选项1(这就是为什么我不确定选项2中的那个部分)。

答案 2 :(得分:0)

是的,你绝对可以这样做。

事实上,它可以提高清晰度并减少混乱。

答案 3 :(得分:0)

如果我记得正确,synchronized是一个监视器,它授予只有一个线程可以在同一个JVM中的任何给定时间访问该对象。所以我认为你只访问shardResouce,在shardResouce上同步就足够了。

答案 4 :(得分:0)

就个人而言,我通常不会在任意锁上同步。也就是说,我通常会按照你的第二种方法做点什么:

private static final MyType sharedResource = MyType();
...
synchronized(sharedResource) {
    //do stuff with sharedResource
}

当然,在运行同步代码之前,必须获取目标对象的锁。通常,我将锁定“向下”更进一步,可以这么说。意思是,我会同步“sharedResource”中的方法。如:

public class MyType {

    public void synchronized doWork() {

    }
}

但是当谈到这种事情时,很难进行概括,因为每条规则都有例外。最后,您的整体架构要求将决定锁定应该发生的位置。对我来说,大多数情况下,我发现自己正在同步访问共享资源的顶级方法,因此锁定一个只执行锁定的对象更为罕见。

编辑:小语法修正