5

好的,我知道这可能是对线程如何真正工作的理解不好,但是直到有人帮助我理解我才会相信这是一个错误:)

在我的 Main 类及其 main() 方法中,我有:

public static void main(String args[]){
    StoneBucket stoneBucket = new StoneBucket();    
    StonePutter spRunnable   = new StonePutter(stoneBucket);
    StoneThrower stRunnable  = new StoneThrower(stoneBucket);
    StoneThrower stRunnable2 = new StoneThrower(stoneBucket);

    //Create the Threads that will take the Runnables as arguments
    Thread puttingThread = new Thread(spRunnable);
    Thread throwingThread = new Thread(stRunnable);
    Thread throwingThread2 = new Thread(stRunnable);

    puttingThread.setName("Putter");
    throwingThread.setName("Thrower 1");
    throwingThread2.setName("Thrower 2");
    [...]

然后在我的 StoneThrower 课上

public class StoneThrower implements Runnable{

private StoneBucket sb;
private String name;

public StoneThrower(StoneBucket _sb){
    this.sb = _sb;
}   

public void run(){

    name = Thread.currentThread().getName();        
    System.out.println("T::"+name+" started...");       
    int count = 0;      
    while(true){
            [...]

当我编译并运行这段代码时,我得到:

2个线程的屏幕截图...

所以,我的问题是为什么这两个线程都返回相同的名称currentThread().getName()?当它们被创建时,它们被分配了名称,threadX.setName("XXX")并且这些可运行文件通过调用开始threadX.start()......有人可以澄清一下吗?

编辑:我接受了正确的答案,因为将 stRunnable 更改为 stRunnable2 行为符合预期。现在真正的问题是为什么会发生这种情况。我创建了两个线程并分别启动它们。run() 方法(在创建线程时调用一次)如何返回错误的名称?

4

2 回答 2

9

发生这种情况是因为您将线程名称存储nameStoneThrower. 由于并发性,第二个线程覆盖name了第一个线程刚刚设置的值,并且它们都输出相同的值。

这是你的场景:

1. Thread1#start
2. Thread2#start
3. Thread1#runnable#run -> runnable.name = 'Thrower 1'
4. Thread2#runnable#run -> runnable.name = 'Thrower 2' // overrides
5. Thread1#runnable#run -> System.out.println(runnable.name)
6. Thread2#runnable#run -> System.out.println(runnable.name)
于 2012-11-28T21:03:10.377 回答
5

您使用相同的可运行对象创建两个线程:

Thread throwingThread = new Thread(stRunnable);
Thread throwingThread2 = new Thread(stRunnable);
                                    ^^^^^^^^^^ stRunnable2?

您将线程名称存储在Runnable对象的实例变量中。由于该对象由两个线程共享,因此要执行的第二个线程会name = Thread.currentThread().getName()用自己的名称覆盖第一个线程的名称。

于 2012-11-28T20:53:54.763 回答