为什么Java和C#为每个对象添加了内在锁?
使每个对象都可锁定看起来像是一个设计错误:为什么Java和C#为每个对象添加了内在锁?,c#,java,synchronization,locking,C#,Java,Synchronization,Locking,使每个对象都可锁定看起来像是一个设计错误: 您为创建的每个对象都增加了额外的成本,即使您实际上只在一小部分对象中使用它 锁的用法变得隐式,使得lockMap.get(key).Lock()比在任意对象上的同步更具可读性,例如,synchronize(key){…} 同步方法可能会导致用户使用同步方法锁定对象的细微错误 您可以确定,当将对象传递给第三个API时,它的锁没有被使用 乙二醇 更不用说每个对象的名称空间污染(在C中,至少方法是静态的,在Java同步原语中必须使用wait,而不是在对象中重
lockMap.get(key).Lock()比在任意对象上的同步更具可读性,例如,synchronize(key){…}
wait
,而不是在对象中重载wait
。)
然而,我相信这种设计是有原因的。内在锁的最大好处是什么?实际上,您在每个对象中只引用了该监视器;只有在使用synchronization=>时才创建真正的监视器对象,不会丢失太多内存
另一种方法是将手动监视器添加到您需要的类中;这将使代码变得非常复杂,并且更容易出错。Java已经用性能换取了生产力。一个好处是退出
同步的
块时自动解锁,即使是例外。我假设,与toString()一样,设计者认为好处大于成本
很多决策都必须做出,很多概念都未经测试(检查异常确认!),但总的来说,我相信它比显式的“锁定”对象更自由、更有用
另外,您是否向语言或库添加“锁定”对象?看起来像是一种语言构造,但库中的对象很少(如果有的话?)有特殊处理,但将线程更多地视为库构造可能会减慢速度
您为创建的每个对象都增加了额外的成本,即使您将
实际上,它只在一小部分物体上使用
这是由JVM实现决定的。他说,,“监视器与对象的关联可以通过各种方式进行管理,这些方式超出了本规范的范围。例如,监视器可以与对象同时分配和解除分配。或者,它可以在线程尝试以独占方式访问对象时动态分配,并在稍后某个时间当对象的监视器中没有线程时释放。”
我还没有看过很多JVM源代码,但是如果有任何一个普通JVM处理这个问题效率低下,我会非常惊讶
锁的用法变得隐式,使用lockMap.get(key).Lock()更简单
在任意对象上比同步更可读,例如同步
(键){…}
我完全不同意。一旦您了解了同步
的含义,它就比一系列方法调用更具可读性
同步方法可能会导致用户锁定
对象的同步方法
这就是为什么您需要了解同步的含义。如果您了解它的功能,那么避免这些错误就变得相当简单了。经验法则:不要在多个位置使用同一个锁,除非这些位置需要共享同一个锁。任何语言的锁/互斥策略都可以这样说
您可以确定,当将对象传递给第三个API时
锁未被使用
对。这通常是一件好事。如果它被锁定,应该有一个很好的理由来解释它被锁定的原因。其他线程(第三方或非第三方)需要等待轮到它们
如果您在myObject
上进行同步,目的是允许其他线程同时使用myObject
,那么您就错了。如果有帮助,您可以使用myOtherObject
轻松同步同一代码块
更不用说每个对象(在C中)的名称空间污染了#
在Java同步原语中,至少这些方法是静态的
必须使用wait,而不是重载对象中的wait…)
对象
类确实包含一些与同步相关的方便方法,即notify()
、notifyAll()
、和wait()
。您不需要使用它们并不意味着它们没有用处。您可以很容易地抱怨clone()
,equals()
,toString()
,等等。您在#3中的代码实际上很好:synchronized(o){synchronized(o){…}}}
在Java中非常安全,相当于synchronized(o){…}
。线程不会“锁定自己”,或诸如此类的东西,如果这是你所期望的。实际上,我并不期望“为每一个创建的对象额外花费”太多;似乎表明,当您不实际使用同步时,唯一的成本是~2位。@ruakh我知道锁是可重入的,但问题是人们会在不知不觉中使用您使用的同一个锁。做一些事情,比如在一个线程中锁定映射对象,然后在另一个线程中放入一些东西(已同步)。@LouisWasserman成本不仅以字节为单位,成本还包括API重量、代码大小(在没有同步支持的情况下,为VM提供更大的问题)等等。总之,我看不到任何好处。亲爱的收信人:,我在寻找拥有内在锁的好处和设计考虑。如何改进答案以重新打开它?是的,但这可以通过同步块接受Locker
接口来实现。@ElazarLeibovich只能猜测,但这会使编译器更复杂。而且它可能会使内部JVM特性(如线程转储)更加复杂
class Syncer {
synchronized void foo(){}
}
...
Syncer s = new Syncer();
synchronize(s) {
...
}
// in another thread
s.foo() // oops, waiting for previous section, deadlocks potential