-5

该程序创建线程 t0,它产生线程 t1,随后线程 t2 和 t3 被创建。线程执行后t3,应用程序永远不会返回到之前产生的其他线程(t0,t1,t2)并且它们被卡住。

为什么线程t0、、t1t2挂起?

     public class Cult extends Thread 
            {  
                private String[] names = {"t1", "t2", "t3"};
                static int count = 0;
                public void run() 
                {
                    for(int i = 0; i < 100; i++) 
                    {
                        if(i == 5 && count < 3) 
                        {
                            Thread t = new Cult(names[count++]);
                            t.start();
                            try{
                                Thread.currentThread().join();
                            }
                            catch(InterruptedException e)
                            {
                                e.printStackTrace();
                            }
                        }
                        System.out.print(Thread.currentThread().getName() + " ");
                    } 
                 }

                 public static void main(String[] a`)
                 {
                     new Cult("t0").start();
                 }
            }
4

2 回答 2

2

你错过的最重要的一点:

Thread.currentThread().join();

join源代码中的方法使用方法isAlive

public final synchronized void join(long millis) 
    ...
    if (millis == 0) {
        while (isAlive()) {
        wait(0);
        }
    ...
    }

这意味着Thread.currentThread().join()只有在Thread.currentThread()死亡时才会返回。

但是在您的情况下,这是不可能的,因为您正在运行的代码Thread.currentThread()本身就有这种代码的和平Thread.currentThread().join()。这就是为什么在线程 3 完成后你的程序应该挂起并且此后什么都没有发生。

在此处输入图像描述

于 2013-08-13T22:20:56.883 回答
1

为什么线程 t0、t1 和 t2 被挂起?线程 t3 的执行完成。

t3完成,因为它没有尝试分叉第四个线程,因此没有尝试join()使用它自己的线程。以下行将永远不会返回,因此 t0、t1 和 t2 都停在那里并永远等待:

Thread.currentThread().join();

这是要求当前线程等待自己完成,这是行不通的。我怀疑您的意思是说t.join();哪个正在等待刚刚分叉的线程完成。

以下是关于您的代码的其他一些想法,没有明显的顺序:

  • 您应该考虑implements Runnable而不是extends Thread. 请参见此处:“实现可运行”与“扩展线程”

  • 您在多个线程中使用共享static变量count而没有任何锁定保护。最好的解决方案是使用 aAtomicInteger而不是 a int。您可能在这里没有问题,因为每个线程都在修改count然后分叉另一个线程,但是如果您尝试分叉 2 个线程,由于数据竞争条件,这将是一个真正的问题。

  • 我不确定你为什么只产生另一个线程if(i == 5 && count < 3)i只会在那个循环中出现5 一次。这真的是你的意图吗?

  • String[] names = {"t1", "t2", "t3"};建议在类的顶部声明字段。否则他们会被埋没在代码中而迷失方向。

  • main你启动一个Cult线程,然后主线程完成。这是不必要的,您可以直接调用cult.run();main使用主线程。

  • Cult(String s) { super(s); }有一个构造函数调用具有相同参数的超级构造函数是没有意义的。这个可以去掉。

  • 这是有争议的,但我倾向于将main方法放在类的顶部而不是埋没它,因为它是“入口”方法。与构造函数相同。那些应该在方法之上run()

  • catch(Exception e) {}是一个非常糟糕的模式。至少你应该做一个e.printStackTrace();或以某种方式记录它。捕获并丢弃异常隐藏了很多问题。此外, catchException应更改为catch(InterruptedException e). 你想限制你的 catch 块只是块抛出的异常,否则如果你在某处复制并粘贴该块,这可能会再次隐藏问题。

  • 更多是一种好的做法,但永远不要使用3必须匹配另一个数据项的常量。在这种情况下,最好使用names.lengthwhich is 3。这意味着如果您想增加线程数,则无需更改代码中的 2 个位置。您也可以使用该名称"t" + count并完全摆脱该names数组。

于 2013-08-13T22:01:12.710 回答