java中的bug线程处理

时间:2009-10-31 14:50:27

标签: java concurrency multithreading

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(“总是第一次”);影响并发?

4 个答案:

答案 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();之后放置“总是第一个”句子,你可能得到你期望的结果:)