为什么Java和C#添加内部锁到每一个对象?(Why did Java and C# add int

2019-06-27 13:32发布

使每个对象可锁定看起来像一个设计错误:

  1. 你增加额外的成本创建的每个对象,即使你实际上只在对象的一小部分使用它。
  2. 锁的使用成为隐式的,具有lockMap.get(key).lock()大于在任意对象同步的可读性,例如, synchronize (key) {...}
  3. 同步方法可能会导致使用者的细微误差与同步方法锁定所述对象
  4. 你可以肯定的是传递对象到3号的离别API时,不使用它的锁。

例如

class Syncer {
    synchronized void foo(){}
}
...
Syncer s = new Syncer();
synchronize(s) {
    ...
}
// in another thread
s.foo() // oops, waiting for previous section, deadlocks potential
  1. 且不说每个命名空间polution和每一个对象(在C#,至少方法是静态的,在Java同步原语必须使用await ,不超载waitObject ...)

不过我敢肯定有一些原因的设计。 什么是内在的锁大有裨益?

Answer 1:

你增加额外的成本创建的每个对象,即使你实际上只在对象的一小部分使用它。

这是由JVM实现确定。 在JVM规范说,“监视器与对象的关联可以在不属于本规范的范围不同的方式进行管理。例如,显示器可以进行分配,并在同一时间为对象释放。或者,可当一个线程试图获得对对象独占访问,并在以后的某个时间被释放时,没有线程保持在监视的对象时动态分配“。

我没有太多在JVM源代码看着,但我会非常惊讶,如果任何常见的JVM处理这个低效。

锁的使用成为隐式的,具有lockMap.get(键).lock()比上任意对象同步的可读性,例如,同步(键){...}。

我完全不赞同。 一旦你知道的意思synchronize ,它比方法调用链更具有可读性。

同步方法可能会导致使用者的细微误差与同步方法锁定所述对象

这就是为什么你需要知道的意思synchronize 。 如果你了解它做什么,然后避免这些错误变得相当微不足道。 经验法则:除非那些地方需要共享同一个锁,不要使用在多个位置相同的锁。 同样的事情可以说任何语言的锁定/互斥策略。

你可以肯定的是传递对象到3号的离别API时,不使用它的锁。

对。 这通常是一件好事。 如果它被锁定,应该有一个很好的理由,为什么它是锁着的。 其他线程(第三方或不)需要等待他们的圈。

如果您在同步myObject使用允许其他线程使用的意图myObject同时,你这样做是错误的。 使用你可以很轻松地同步同一个代码块myOtherObject是否会有所帮助。

且不说每个命名空间polution和每一个对象(在C#,至少方法是静态的,在Java同步原语必须使用伺机,而不是在对象超载等待......)

Object类不包括与同步一些方便的方法,即notify() notifyAll()wait() 你有没有使用它们需要的,但这并不意味着他们是没有用的。 你可以很容易地抱怨clone() equals() toString() ,等等。



Answer 2:

其实你只需要参照每个对象监控; 只有当您使用同步=>没有这么多的内存丢失创建真正的监控对象。

另一种方法是手动添加监视那些你需要的类; 这将非常代码复杂化,并会更容易出错。 Java已经换了生产率表现。



Answer 3:

一个益处是从出口自动解锁synchronized块,即使通过异常。



Answer 4:

我认为像的toString(),设计师认为典型应用该类超支大于成本。

决策地段必须作出和大量的概念是未经检验的(经过例外 - 确认!),但总体来说,我敢肯定,这几乎是免费的,不是一个明确的“锁”对象更加有用。

另外你添加一个“锁定”对象的语言或图书馆? 似乎是一个语言结构,但在库中很少的对象(如果有的话?)有特殊的治疗,但治疗多线程作为文库构建有可能放缓下来的东西..



文章来源: Why did Java and C# add intrinsic lock to every object?