为什么这些是如此基本,以至于每个对象都必须拥有它们,并且拥有它们是否会对性能产生影响(大概是存储在其中的某些状态)?
tl;dr:它们是线程安全方法,相对于其价值而言,它们的成本很小。
这些方法支持的基本现实是:
- Java始终是多线程的。示例:查看使用 jconsole 或 jvisualvm 的进程使用的线程列表。
- 正确性比“性能”更重要。当我给项目评分时(很多年前),我曾经不得不解释“很快得到错误的答案仍然是错误的”。
从根本上说,这些方法提供了一些钩子来管理同步中使用的每个对象监视器。具体来说,如果我有一个特定的方法,我可以用来产生那个监视器(例如,如果我需要另一种方法来完成计算,然后才能继续)。在这种情况下,这将允许另一个被阻止的方法等待该监视器继续。synchronized(objectWithMonitor)
objectWithMonitor.wait()
另一方面,我可以使用让等待监视器的线程知道我将很快放弃监视器。但是,在我离开同步块之前,它们实际上无法继续。objectWithMonitor.notifyAll()
对于特定示例(例如,长双打列表),您可能会担心监视机制的性能或内存受到影响,以下是您应该考虑的一些要点:
- 首先,证明这一点。如果你认为核心Java机制(如多线程正确性)有重大影响,那么你的直觉很有可能是错误的。首先衡量影响。如果情况很严重,并且您知道您永远不需要在单个 Double 上进行同步,请考虑改用 Doubles。
- 如果你不确定你,你的同事,未来的维护程序员(一年后可能是你自己)等,永远不会需要对你的数据进行精细的粒度访问,那么很有可能把这些监视器拿走只会让你的代码不那么灵活和可维护。
跟进以响应有关每个对象与显式监视对象的问题:
简短的回答:@JonSkeet:是的,移除显示器会产生问题:它会产生摩擦。保持这些监视器提醒我们,这始终是一个多线程系统。Object
内置对象监视器并不复杂,但它们是:易于解释;以可预测的方式工作;并且目的明确。 是一个明确的意图声明。如果我们强制新手编码人员以独占方式使用并发包,则会引入摩擦。该软件包中包含哪些内容?什么是信号量?分叉连接?synchronized(this)
新手编码人员可以使用对象监视器编写体面的模型-视图-控制器代码。,并且可用于实现朴素(在简单,可访问但可能不是前沿性能的意义上)线程安全。规范的例子是其中一个双精度值(由OP提出),它可以让一个线程设置一个值,而AWT线程获取值以将其放在JLabel上。在这种情况下,没有充分的理由创建一个显式的附加对象只是为了有一个外部监视器。synchronized
wait
notifyAll
在稍微高一点的复杂性下,这些相同的方法作为外部监视方法很有用。在上面的例子中,我明确地做到了这一点(参见上面的objectWithMonitor片段)。同样,这些方法对于将相对简单的线程安全性放在一起非常方便。
如果你想变得更加复杂,我认为你应该认真考虑阅读Java并发实践(如果你还没有的话)。读和写锁非常强大,而不会增加太多额外的复杂性。
重点:使用基本的同步方法,您可以利用具有线程安全性的现代多核处理器所支持的大部分性能,而无需大量开销。