我在Java语言规范17.1中读到这个:
“Java中的每个对象都是关联的 有一个监视器,一个线程可以 锁定或解锁。“
为什么一定?这不是说java对象太重了吗?我不知道为什么像一个字符串这样的对象应该自然是一个监视器!
编辑:
我认为结束了,是的,Java有一个关键字同步,因为 EVERY 对象可能有一个同步方法,所以有必要关联 EVERY 对象监视器。
但是这似乎不是一个非常好的解决方案,通常你需要为一个类多一个互斥量,除了那个非常简单的pojo类。
答案 0 :(得分:4)
你的假设有一些道理,在经典着作“Java Concurrency in Practice”(由大师Brian Goetz,Tim Peierls,Joshua Bloch,Joseph Bowbeer,David Holmes,Doug Lea撰写)中他们写道:
每个对象都有一个内置锁的事实只是一个方便 这样您就不需要显式创建锁定对象。回想起来, 这个设计决定可能是一个糟糕的决定:它不仅可以 令人困惑,但它迫使JVM实现者在两者之间进行权衡 对象大小和锁定性能。
(第2.4章:带锁的守卫状态)
答案 1 :(得分:2)
你的根本问题在于假设每个对象都内置了某种Monitor
,等待某些代码使用它。实际上,大多数对象从未用作监视器,因此在使用监视器之前不必创建监视器。不要将此功能实现为具有private Monitor monitor
字段的每个对象,而应将其视为具有全局HashMap<object, Monitor> monitors
的JVM。
可能的实现是这样的:每当输入synchronized
块时,JVM就会在地图中查找同步对象(monitors
)。如果找到它,它将使监视器使用。如果找不到,则进入专用于地图的关键部分。然后它再次查找对象,因为另一个线程可能在先前的检查和进入临界区之间创建了它。如果它仍然不存在,它会为同步对象创建监视器并离开临界区。
答案 2 :(得分:1)
这是一种非常聪明的方法,可以实现一切线程安全。我认为重量有点主观;例如,在Java中,该对象仅获得一个可通知的等待队列,而使用synchronize
明确指定了互斥。
C#使用类似的方法来强制执行线程安全,所以很明显MS也认为这是一个非常聪明的解决方案。替代方案是什么?手写的信号量和互斥量?在Java中,考虑到大多数生产级应用程序(即服务器,服务等)具有多线程,这将是一场噩梦。让语言为你做一切艰难/无聊的事情真是太棒了。
答案 3 :(得分:0)
线程同步对于确保正确的结果是必要的,因为它们可能是竞赛条件。
那么,如果它没有液晶显示器或CRT显示器那么重,那会没问题吗?
答案 4 :(得分:0)
我同意任何对象都可以成为锁的概念令人困惑。许多人认为synchronized(obj)
可以保护obj
不被同时访问。如果我们从州获得单独的锁,那么这种误解的可能性就会降低。
java内存模型中的文本不显示使用任意对象或任何对象作为同步原语的任何重要性。也许为此目的使用物体是经济的设计。
它也可以使用整数作为锁。实际上synchronized(493725)
因为每个对象都在内部与它的地址(它的地址)相关联,所以JVM可能会这样做。对于未同步的对象,开销为零。
使用java.util.concurrent类,如果您不喜欢它,则不再需要这样的synchronized(obj)
。