Java 这个线程join()是如何工作的?
我是java新手,目前正在使用一个培训材料,下面的代码生成以下输出:Java 这个线程join()是如何工作的?,java,multithreading,Java,Multithreading,我是java新手,目前正在使用一个培训材料,下面的代码生成以下输出: Run. Run. doIt 它是如何运行的。两次?t.join()是如何工作的 t.start()开始执行新线程,新线程将在t.run()中执行代码。但是对t.start()的调用将立即返回;它不会等待该线程完成执行run()。t.start()返回后,主线程运行t.run()。最后,它将等待t线程完成,这就是t.join()所做的。此方法不会立即返回,而是等待线程完成。(碰巧的是,在这种情况下速度会非常快——但可能需要几
Run. Run. doIt
它是如何运行的。两次?t.join()是如何工作的
t.start()
开始执行新线程,新线程将在t.run()
中执行代码。但是对t.start()
的调用将立即返回;它不会等待该线程完成执行run()
。t.start()
返回后,主线程运行t.run()
。最后,它将等待t
线程完成,这就是t.join()
所做的。此方法不会立即返回,而是等待线程完成。(碰巧的是,在这种情况下速度会非常快——但可能需要几分钟、几个小时甚至永远。)
控制流如下所示:
Thread A
|
+- t.start() ---> starts Thread B
+- t.run() +- t.run()
| |
+- t.join() waits for B |
| to finish |
| \------> +- Thread B stops
+- t.doIt()
+- Thread A stops
这是一个无关的电话
当您使用t.start()
启动线程时,它是独立启动的。这会将“运行”打印到屏幕上
然后,t.run(
运行线程的run(
方法,该方法也会打印run
。“run”的这两个打印可以是任意顺序
最后,我们调用t.join
。这将等待线程终止(在通过join设计打印线程之后,以及在打印from run之后,因为run
调用在前和阻塞之前)
在join
之后,doIt函数以阻塞方式调用
简而言之,主线程和t
线程都打印run
,然后主线程等待t
线程完成打印doIt
尽管许多调用是t
线程的一部分,但线程的行为在某种程度上独立于实例。方法start()
会导致线程对象执行(当它执行时是不确定的),JVM会调用run()
方法
但是您也可以直接调用run()
,这就是为什么run()
执行两次
调用join()
RRuunn.. doIt
真讨厌。这是来自Safeway编程学院的吗?我推荐线程上的“编程洞穴”视频-为什么我的评论总是吸引“粗鲁或无礼”的旗帜?我并不是在侮辱任何人(也许除了编写该示例的讲师)。作为记录,我通常不赞成通过使用坏代码来教人们好的编程。@RobertHarvey也许这个例子是为了说明start()
调用run())
,或者说线程
仍然是一个具有可调用方法的常规类,或者其他什么。我同意这是一个令人憎恶的问题。这并没有什么真正的答案。@iamnotmaynard我认为这是显而易见的,但我现在已经解释清楚了连接确保在执行之前打印两条运行消息。@inc哦,是的……太早了:/@Bohemian我是有点口语化。收紧了语言。需要注意的另一点是调用start()实际上并没有启动线程。它只是请求JVM启动它;启动时间是不确定的。@yshavit:可能是个愚蠢的问题,但这是我的理解:run()方法是线程的默认方法,但可以重写。因此,每当线程启动时,它都只自动执行run()。在这里,在两个run()完成后,doIt()会被显式调用,因此它也会运行。这是对的吗?如果是,为什么运行()呢在B中自动执行,但从OS/JVM实现的角度来看,在A中显式调用?@Bohemian,您可能是对的。从Java的角度来看,这是一个迂腐、无意义和错误之间的区别。文档中说它“导致此线程开始执行”。JLS§17说“当start()启动时,线程将启动”方法在相应的线程对象上被调用。“当然,当run()
中的第一个操作被调度时是另一个问题。@mankand007你是对的。但是要认识到的是,即使run()
是“特殊的”因为它是一个新线程将执行的方法,它也是一个普通的、普通的方法,您可以在任何地方和任何您喜欢的地方显式调用。想象一下,如果我有一个方法public void goFoo(){foo();}
。调用goFoo()
将导致foo()
运行,但是foo()
也是一个可以显式调用的普通方法。同样的想法。这是否意味着即使没有t.run()也可以,结果将是相同的?@mankand007 No.运行
输出中的一个将被忽略,因为打印从未被调用两次。请尝试并查看。PrintStream.print
委托给一个私有的,它是同步的。因此,除非您将System.out
替换为一个不同步的自定义子类PrintStream
ronize,你不会在实践中看到这一点。不过,PrintStream
合同并不能保证这一点;它只是一个方便的“不需要,但在实践中有效”的东西。
t.run();
RRuunn.. doIt