【问题标题】:Thread getName() returns wrong name线程 getName() 返回错误的名称
【发布时间】:2012-11-28 20:51:04
【问题描述】:

好的,我知道这很可能是对线程的真正工作原理的理解不好,但在有人帮助我理解之前,我会相信这是一个错误 :)

在我的 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){
            [...]

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

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

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

【问题讨论】:

  • 你能在你开始线程的地方发布一段代码吗?

标签: java multithreading thread-safety


【解决方案1】:

发生这种情况是因为您将线程名称存储在 StoneThrower 的实例变量 name 中。由于并发性,第二个线程会覆盖第一个线程刚刚设置的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)

【讨论】:

  • 终于有了合理的诊断。 +1
  • 我添加了一条评论来询问这个问题。非常感谢你,很抱歉@NPE 拿了正确的答案标志:(
  • 尚未看到StoneThrower 的完整实现,但如果将name 转换为局部变量,很可能您只能拥有它的一个实例。
【解决方案2】:

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

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

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

【讨论】:

  • 创建具有相同 Runnable 的单独线程本身不会强制线程具有相同的名称。其他事情正在发生。
  • @TedHopp:在这种情况下,确实如此。线程名称存储在Runnable 对象的实例变量中。由于对象被两个线程共享,第二个执行name = Thread.currentThread().getName()的线程获胜。
  • 是的,但是当我发表评论时,这不是您回答的一部分。通过编辑,它现在赢得了我的 +1。
  • @NPE.. 实际上你也应该删除第一部分,因为它与结果无关。
  • @RohitJain - 第一部分是相关的。如果线程是使用单独的 Runnable 实例创建的,则不会有名称覆盖。
猜你喜欢
  • 1970-01-01
  • 2019-10-13
  • 2014-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-02
  • 2018-04-23
  • 2021-03-31
相关资源
最近更新 更多