多线程程序输出不符合预期

时间:2013-12-17 01:06:20

标签: java multithreading

我写了一个小程序,我将线程名称存储在类级字段中并打印它。

public class ThreadClass implements Runnable {

    private String threadName = null;

    @Override
    public void run() {
        System.out.println(" thread name " + threadName);
        System.out.println(" current thread  >>>>>> "
                + Thread.currentThread().getName());
        threadName = Thread.currentThread().getName();
    }
}

我写了一个测试类,在那里我创建了10个线程并启动它们。

public class ThreadController {
    public static void main(String[] args) {
        ThreadClass threadClass = new ThreadClass();
        Thread t1 = new Thread(threadClass, "T1");
        Thread t2 = new Thread(threadClass, "T2");
        Thread t3 = new Thread(threadClass, "T3");
        Thread t4 = new Thread(threadClass, "T4");
        Thread t5 = new Thread(threadClass, "T5");
        Thread t6 = new Thread(threadClass, "T6");
        Thread t7 = new Thread(threadClass, "T7");
        Thread t8 = new Thread(threadClass, "T8");
        Thread t9 = new Thread(threadClass, "T9");
        Thread t10 = new Thread(threadClass, "T10");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();
        t7.start();
        t8.start();
        t9.start();
        t10.start();
    }
}

我得到了以下输出。

 thread name null
 thread name null
 thread name null
 current thread  >>>>>> T1
 current thread  >>>>>> T6
 current thread  >>>>>> T2
 thread name T2
 thread name T2
 thread name null
 thread name null
 thread name null
 current thread  >>>>>> T4
 current thread  >>>>>> T7
 current thread  >>>>>> T8
 current thread  >>>>>> T9
 thread name T1
 current thread  >>>>>> T5
 thread name T1
 current thread  >>>>>> T3
 current thread  >>>>>> T10

我怀疑的是,如果每个线程都创建了一个字段变量的本地副本,那么为什么我并不总是将线程名称变为null。 对不起,如果这听起来像一个愚蠢的问题,但我正在努力学习线程。

3 个答案:

答案 0 :(得分:3)

线程将创建其访问的字段的本地副本。在您的实现中,所有线程都试图访问实例threadClass中的相同字段,这就是为什么它始终不是null

如下所示更改您的来源,您将获得预期的行为。

Thread t1 = new Thread(new ThreadClass(), "T1");
Thread t2 = new Thread(new ThreadClass(), "T2");
Thread t3 = new Thread(new ThreadClass(), "T3");
Thread t4 = new Thread(new ThreadClass(), "T4");
Thread t5 = new Thread(new ThreadClass(), "T5");
Thread t6 = new Thread(new ThreadClass(), "T6");
Thread t7 = new Thread(new ThreadClass(), "T7");
Thread t8 = new Thread(new ThreadClass(), "T8");
Thread t9 = new Thread(new ThreadClass(), "T9");
Thread t10 = new Thread(new ThreadClass(), "T10");

答案 1 :(得分:1)

虽然您已命名变量threadName,但它与Thread对象的名称无关。如果使用Thread构造函数方法将String作为Thread名称传递,则可以使用Thread.currentThread()。getName()返回此String,但不会更改threadName变量。

如果您希望以编写代码的方式使用变量,那么您应该在ThreadClass中使用一个接收String的构造函数并设置threadName,如下所示:

public ThreadClass(String name){
    this.threadName = name;
}

你可以像这样使用这个构造函数:

Thread t1 = new Thread(new ThreadClass("T1"));

请注意,如果您仍想使用Thread.currentThread()。getName(),则必须执行以下操作:

Thread t1 = new Thread(new ThreadClass("T1"),"T1-name for getName");

干杯

答案 2 :(得分:0)

你这样做:

System.out.println(" thread name " + threadName);

之前:

threadName = Thread.currentThread().getName();

因此,您所拥有的输出在消息中是正常的:thread name null。每个线程一旦启动就会打印线程名称为null。

由于您对所有线程使用相同的ThreadClass实例,因此在一个中更改类变量threadName也将在其他线程中更改。 实际上,只有ThreadClass的一个实例(而且是threadName的一个实例),并且每个线程都使用对ThreadClass的引用。

这就是为什么你看到这个语句打印所有线程名称的原因:

System.out.println(" current thread  >>>>>> " + Thread.currentThread().getName());

但不是这样:

System.out.println(" thread name " + threadName);

了解Java如何处理对象和对象的引用将有助于您使用线程。