Sun 的 Thread.join 方法是否因使用 Thread 对象进行同步而被破坏?
通过运行测试程序和查看源代码,可以清楚地看出,Sun 实现的该方法并不是简单地为指定线程让出时间,而是实际上首先尝试获取线程对象上的监视器。 具体来说,该方法被实现为“同步”。
请注意,wait 和 notify 方法也需要监视器,但与 join 不同,调用者有责任在调用之前获取监视器,文档中也明确如此说明。 Javadoc 中没有记录 join 依赖于监视器的事实,尽管做出推断可能是很自然的。
文档足够清楚吗?
此外,如果线程由于某种原因无法获取监视器,它将挂起,甚至可能永远挂起。 在等待监视器时,线程是不可中断的,并且不会像文档中所述抛出 InterruptedException。 另一方面,目前还不清楚为什么线程无法获取监视器,除非出现编程错误。
担心显示器争用是否合理?
最后,使超时操作依赖于获取监视器似乎是不合适的,除非可以保证获取监视器的任务本身会超时。
依赖于 join() 的监视器是一个合理的实现吗? 是否有可能以其他方式实现它?
By both running test programs and looking at source code, it is clear that the method, as implemented by Sun, does not simply yield time to the specified thread, but actually it first attempts to obtain a monitor on the thread object. Specifically, the method is implemented as "synchronized."
Note that the wait and notify methods also require the monitor, but unlike join, it is the caller's responsibility to obtain the monitor before making the call, and the documentation clearly says so. The fact that join depends on the monitor is not documented in the Javadocs, although perhaps it is natural to make the inference.
Is the documentation clear enough?
Additionally, if the thread can't obtain the monitor for some reason, it will hang, maybe forever. While waiting for the monitor, a thread is not interruptible, and will not throw the InterruptedException as described in the documentation. On the other hand, it is not clear why a thread wouldn't be able to obtain the monitor except in the case of a programming error.
Is it reasonable to worry about contention over the monitor?
Finally, it seems inappropriate to make the operation of a timeout dependent on obtaining a monitor, unless it can be guaranteed that the task of obtaining the monitor will itself time out.
Is depending on the monitor for join() a reasonable implementation? Is it even possible to implement it any other way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Thread.join
调用wait
,这会释放监视器。 由于这意味着“加入”线程也不会阻止任何其他线程调用 join,因此我怀疑这会回答您的大多数其他查询。 它不会阻止另一个调用者在线程的监视器上同步(公共监视器的乐趣),但这意味着常见情况工作正常。只是为了证明您的第一点是错误的,这里有一个示例,它创建 10 个线程,每个线程在主线程上等待 5 秒。 (请忽略可怕的异常吞噬和滥用
Date
。它仅用于研究线程行为。)如果运行它,您将看到所有线程开始和结束等待几乎同时。 如果你的担忧是有根据的,你就不会像你那样得到“交错”的结果。
Thread.join
callswait
, which releases the monitor. As this means a "joining" thread doesn't block any other thread from calling join as well, I suspect this answers most of your other queries. It doesn't prevent another caller from synchronizing on the thread's monitor (oh the joys of public monitors) but it means that the common case works fine.Just to demonstrate that your first point is wrong, here's an example which creates 10 threads which each wait on the main thread for 5 seconds. (Please ignore the horrible exception swallowing and abuse of
Date
. It's only intended to be used to study the threading behaviour.)If you run that, you'll see that all the threads start and end their waits virtually simultaneously. You don't get the ends "staggered" as you would if your concerns were well-founded.
它不会屈服于加入的线程,它只是等待,假设线程在某个时刻将运行完成。 在线程上使用 join() 并不会使该线程比任何其他准备运行的线程更有可能运行。
线程被设计为同时工作。 如果他们都等待,他们会同时等待。 等待线程不会使另一个线程等待更长时间。
除非您希望这种情况发生,否则不会。
您建议的情况只有在线程获得该线程的锁然后永远持有它而无需等待时才会发生。 这是一个编程错误。 恕我直言,您永远不应该直接获取线程对象的锁。
Java 不能保护您免受您自己的 JVM 中的恶意代码的侵害。
如果它被无限期锁定,是的。
永远不要锁定线程对象,没有理由需要这样做,并且不会遇到此问题。 如果您想开始寻找可能使其他开发人员或您自己感到困惑的各种方法,那么恕我直言,Threads 不是您开始的地方。
线程 2 一旦调用 wait 就释放监视器。 它不能同时等待和保持监视器。
不。 请参阅之前的评论。
它会。
是的。 但这是一种非常罕见的情况。 如果您使用编写的代码,您所指的情况最多只会存在几毫秒。
您可以使用最新的 Java 5 并发库执行您的建议。
但是,我建议您不要假设超时保证精确到毫秒。 此方法使用的 currentTimeMillis() 在 Windows XP 上仅精确到约 16 毫秒,并且等待/睡眠通常比 Linux 上小超时应有的时间长 2 毫秒。
恕我直言,如果您需要超过 40 毫秒的精度,您可能会遇到困难,但是如果您解决这个问题,您会发现这不一定是问题。
It doesn't yield to the thread joined, it just waits with the assumption that at some point the thread will run to completion. Having a join() on a thread does not make it more likely to run than any other thread ready to run.
Threads are designed to work concurrently. If they all wait, they do so concurrently. A waiting thread does not make another thread wait longer.
not unless you intend this to happen.
The situation you suggest could only occur if a thread obtains a lock on the thread and then holds it forever without waiting. This is a programming bug. IMHO You should never obtain a lock on a thread object directly.
Java doesn't protect you from malicious code in your own JVM.
If it is being locked out indefinitely, yes.
Don't ever lock the thread object, there is no reason you should need to, and you won't have this problem. If you want to start looking at every way you could confuse other developers or yourself, then Threads isn't the place you would start IMHO.
Thread 2 releases the monitor as soon as wait is called. It cannot wait and hold the monitor at the same time.
no. see previous comments.
It would.
yes. But this is a very rare condition. If you use the code as written, the situation you refer to will only exist for a few milli-seconds at most.
You can do what you suggest with the more recent Java 5 concurrency libraries.
However, I suggest you shouldn't assume that timeouts are guaranteed to be milli-second accurate. currentTimeMillis() used by this method is only accurate to about 16 ms on Windows XP and wait/sleep is typically 2 ms longer than it should be for small timeouts on Linux.
IMHO If you need accuracy of more than 40 ms you may have difficulty, however if you work around this you will find this doesn't have to be a problem.