通过运行测试程序和查看源代码,可以清楚地看出 Sun 实现的方法并没有简单地让出时间给指定的线程,而是实际上它首先尝试获取线程对象上的监视器。具体来说,该方法实现为“同步”。
请注意,wait 和 notify 方法也需要监视器,但与 join 不同的是,调用者有责任在调用之前获取监视器,文档中明确说明了这一点。 Javadocs 中没有记录加入取决于监视器的事实,尽管做出推断可能是很自然的。
文档是否足够清晰?
此外,如果线程由于某种原因无法获得监视器,它会挂起,也许永远挂起。在等待监视器时,线程不可中断,也不会像文档中描述的那样抛出 InterruptedException。另一方面,除非出现编程错误,否则线程无法获得监视器的原因尚不清楚。
担心争夺监视器是否合理?
最后,让超时的操作依赖于获取监视器似乎是不合适的,除非可以保证获取监视器的任务本身会超时。
依赖于 join() 的监视器是否是一个合理的实现?甚至可以通过任何其他方式实现它吗?
最佳答案
Thread.join
调用 wait
,释放监视器。因为这意味着“加入”线程也不会阻止任何其他线程调用 join,所以我怀疑这会回答您的大多数其他查询。它不会阻止另一个调用者在线程的监视器上进行同步(哦,公共(public)监视器的乐趣),但这意味着常见情况工作正常。
为了证明您的第一点是错误的,这里有一个创建 10 个线程的示例,每个线程在主线程上等待 5 秒。 (请忽略 Date
可怕的异常吞噬和滥用。它仅用于研究线程行为。)
import java.util.*;
public class Test
{
public static void main(String[] args) throws Exception
{
for (int i=0; i < 10; i++)
{
new Thread(new ThreadJoiner(Thread.currentThread(), i))
.start();
}
try
{
Thread.sleep(10000);
}
catch (InterruptedException e) {}
}
private static class ThreadJoiner implements Runnable
{
private final Thread threadToJoin;
int id;
public ThreadJoiner(Thread threadToJoin, int id)
{
this.threadToJoin = threadToJoin;
this.id = id;
}
public void run()
{
try
{
System.out.println("Thread " + id +
" waiting at " + new Date());
threadToJoin.join(5000);
System.out.println("Thread " + id +
" finished waiting at " + new Date());
}
catch (InterruptedException e) {}
}
}
}
如果您运行它,您会看到所有线程几乎同时开始和结束它们的等待。如果您的担忧是有根据的,您不会像您那样“错开”结束。
关于java - Sun 的 Thread.join 方法是否因为使用 Thread 对象同步而损坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/813157/