public class Test extends Thread{
public void hello(String s){
System.out.println(s);
}
public void run(){
hello("I’mrunning...");
}//endofrun()
public static void main(String [] args){
Test t=new Test();
System.out.println("always first");
t.start();
System.out.println("always second but why?");
}
}
我已经运行了30次代码。
为什么“总是第二,但为什么?”总是在控制台上排第二?当调用t.start()时,我们有2个线程。 (2个堆栈):主线程和第二个线程。所以“我跑步”有时必须是控制台上的第二个输出。当我删除“总是第一个”输出语句而不是两个输出时,表现为非确定性(这应该是它的方式)
所以我的想法出了什么问题,为什么是System.out.println(“总是第一次”);影响并发?
答案 0 :(得分:5)
通过首先向控制台写出一些内容,您可能会在JIT编译时发生影响,甚至可能发生类型初始化。我觉得这样的事情改变观察到的顺序是完全不可思议的。看到程序在不同系统和不同JVM上的行为略有不同,我不会感到惊讶。
问题是,这些排序中的任何一个都是完全有效的。你不应该依赖作为一个或另一个,如果它总是以相同的方式发生,那就不是一个错误。 (或者更确切地说,它可能是 - 但它不一定是。)
如果你想确保一个特定的订单,你需要明确地做 - 如果你不介意发生什么顺序,那么没有问题:)
答案 1 :(得分:1)
我已经运行了30次这段代码。
在每个操作系统和硬件组合上再运行70亿次,然后报告您的发现。 30是一个非常低的值永远。
为什么“总是第二,但为什么?”总是在控制台上排第二位?
您有多少个核心?大多数线程调度程序将支持当前运行的线程而不是新生成的线程,特别是在单核上,并且有利于在尽可能晚的时间点在内核之间同步线程(线程对象和System.out需要在OS线程之间传递) )。
鉴于线程不是确定性的,并且大多数操作系统不保证公平性和时效性,它绝不是一个以这种方式表现的错误。
如果要在线程之间进行显式排序,则应使用同步块或java.util.concurrent中更强大的类。如果您想要非确定性行为,但允许其他线程运行,您可以使用Thread.yield()
向调度程序提示。
public static void main ( String [] args )
{
FirstThreadBug t = new FirstThreadBug();
System.out.println ( "always first" );
t.start();
yield();
System.out.println ( "always second but why?" );
}
答案 2 :(得分:0)
为什么“总是第二,但为什么?”总是在控制台上排第二位?
并不总是第二。我设法在大约5次执行代码时生成两个订单。这两个排序都是有效的,线程调度取决于您的操作系统,也可能取决于JVM和硬件。
所以我的想法出了什么问题,为什么是System.out.println(“总是第一次”);影响并发?
你的想法是对的,你的实验误导了你;)
答案 3 :(得分:-2)
System.out.println("always first")
将始终排在第一位,因为它会在第二个线程启动之前 ,因此它永远不会影响并发性。
尝试在 t.start();
之后放置“总是第一个”句子,你可能得到你期望的结果:)