Eclipse中的Run和Debug上的线程run()方法执行不同
Posted
技术标签:
【中文标题】Eclipse中的Run和Debug上的线程run()方法执行不同【英文标题】:Thread run() method execution different on Run and Debug in eclipse 【发布时间】:2015-03-12 22:32:30 【问题描述】:对于以下程序,在 eclipse 上运行和调试时会出现不同的输出。
public class MyClass implements Runnable
public static void main (String[] args) throws Exception
Thread t = new Thread(new MyClass());
t.start();
System.out.print("Started");
t.join();
System.out.print("Complete");
public void run()
for (int i = 0; i < 4; i++)
System.out.print(i);
当作为 java 应用程序运行时,OUTPUT 是
Started0123Complete
签入时调试模式OUTPUT为
0123StartedComplete
有人可以帮忙吗?是因为两个线程吗? main thread
和以t.start()
开头的线程。如果是,那么为什么主线程执行优先级更高?
谢谢
【问题讨论】:
无法保证它将如何在调试/常规模式下运行。如果您在每种模式下多次运行它,您会注意到不同的输出。 我确实尝试了 5,6 次相同的输出。 5 或 6 次没什么,在一个循环中运行 1000 多次,你最终会看到不同的输出 机会:我现在在 1000+ 循环中,但看不出有什么不同 硬件、您的 java 配置、您的操作系统配置有很多变量,您可能只看到Integer.MAX_VALUE
次中的 1 次之间的差异。对于其他配置,它可能是每 100 次中的 1 次。答案应该澄清为什么会这样。
【参考方案1】:
字符串“Started”和整数的打印顺序未定义。在调用start
之后,不能保证run
方法中的代码将在调用join
之前出现的任何其他语句之前或之后执行。这是多线程应用程序的本质。
您在调试模式和运行模式下看到特定输出的事实可能纯属偶然,如果您多次运行代码或在不同平台/JVM 版本上运行代码,可能会发生变化。如果在这种情况下您需要确定性顺序,那么实现它的唯一方法是在调用 start
之前打印一个字符串 before 或引入某种其他类型的信号量来强制线程等待主线程反之亦然。
【讨论】:
实际上这不是您可以实现它的 /only/ 方式,子线程和父线程之间的某种共享互斥锁也可以让您这样做,例如信号量 @MrWiggles touche,修改了我的答案!【参考方案2】:这是巧合。您无法控制线程调度程序。
但是,在调试环境中,debugger 会插入您的代码以检查值和执行情况。这种检查增加了每个线程时间片完成的工作量。
例如,在常规运行中,主线程可能只需要 1 个时间片来创建新的线程对象、启动它并打印Started
消息。然后会发生上下文切换,第二个线程将有机会工作。在调试运行中,主线程只有足够的时间来创建新的线程对象并启动相应的线程。然后会发生上下文切换,另一个线程会做它的事情。
【讨论】:
将接受的答案更改为此,因为这更有意义。【参考方案3】:与是否处于调试模式无关。 无法保证何时执行
System.out.print("Started"); //this is in the main thread
相比
for (int i = 0; i < 4; i++) // this is in the started thread
System.out.print(i);
甚至可以
01Started23Complete
【讨论】:
我喜欢你展示了循环中途停止的可能性。【参考方案4】:是的,因为有 2 个线程,但是输出是不可预测的。 不,主线程没有获得高优先级,因为它的 MAIN。 在多线程中你不能说任何特定的交错执行。
在 Debug 中,我的猜测是您为主线程设置了一个断点,以便它等待,同时其他线程可能已经执行。
【讨论】:
可能是这种情况:) 有没有文章可以帮助更多地理解这一点?如果这真的像你说的那样发生。【参考方案5】:在两个(运行/调试)模式输出将是
开始0123完成
您会看到结果 0123StartedComplete,因为您必须在主线程代码中有调试点,这就是原因。
如果您想更好地理解,请将 run() 方法移至 MyClass 内部,并将调试器点放在 run 方法中,现在您将看到它打印为 Started0123Complete。
在内部,主线程正在创建子线程“t”,当 t.start() 被调用时,它正在等待捕获线程执行的监视器(即 run()),当您在主线程中添加调试语句时,子线程正在进入监视器并执行运行方法,一旦完成,主线程将再次启动。
【讨论】:
这家伙其实是对的……run方法已经在课堂上。我只是将调试点改成运行,但我想了解内部发生了什么 在内部,主线程正在创建子线程“t”,当 t.start() 被调用时,它正在等待捕获线程执行的监视器(即 run())以及添加调试时主线程中的语句,子线程进入monitor并执行run方法,一旦完成,主线程再次启动。以上是关于Eclipse中的Run和Debug上的线程run()方法执行不同的主要内容,如果未能解决你的问题,请参考以下文章