Thread构造函数参数的用途

时间:2013-08-20 14:01:20

标签: java multithreading

我在tutorial website上找到了这段代码:

class NewThread implements Runnable {
   Thread t;
   NewThread() {
      // Create a new, second thread
      t = new Thread(this, "Demo Thread");
      System.out.println("Child thread: " + t);
      t.start(); // Start the thread
   }

   // This is the entry point for the second thread.
   public void run() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Child Thread: " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
     } catch (InterruptedException e) {
         System.out.println("Child interrupted.");
     }
     System.out.println("Exiting child thread.");
   }
}

public class ThreadDemo {
   public static void main(String args[]) {
      new NewThread(); // create a new thread
      try {
         for(int i = 5; i > 0; i--) {
           System.out.println("Main Thread: " + i);
           Thread.sleep(100);
         }
      } catch (InterruptedException e) {
         System.out.println("Main thread interrupted.");
      }
      System.out.println("Main thread exiting.");
   }
}

在下面一行中,参数的目的是什么,this在第一个参数中的含义是什么:

 t = new Thread(this, "Demo Thread");

此代码的预期行为(流程)是什么?

4 个答案:

答案 0 :(得分:0)

t = new Thread(this, "Demo Thread")正在创建一个新线程,该线程传递线程应该执行的java.lang.Runnable实例以及给予线程的名称(在日志记录操作期间常用)。

让实现java.lang.Runnable的类创建线程本身有点奇怪。看一下如何在java.lang.Thread的JavaDoc上使用线程的示例。

答案 1 :(得分:0)

t = new Thread(this, "Demo thread")中使用的构造函数允许传递目标。目标必须是Runnable。作为启动run()的结果,将调用目标的t方法,因此创建并运行Thread。请参阅documentation

答案 2 :(得分:0)

创建新的Thread对象时,必须传入Runnable对象(在run()方法中执行实际工作)作为构造函数的第一个参数。第二个参数是线程的名称。因此,在您的代码中,NewThread类构造函数中的以下行:

t = new Thread(this, "Demo Thread");

使用自身(Thread的实例)作为t任务创建一个名为 Demo Thread 的新NewThread对象Runnable,因为它实现Runnable接口。然后,当调用t.start()时,将调用run()实例NewThread的{​​{1}}方法。

java.lang.Threadjava.lang.Runnable的API文档提供了更多详细信息。

因此,您的代码创建了一个t对象,它在运行子线程循环的构造函数中启动子线程,而主线程循环是由NewThread方法中的其余代码执行。我希望看到子线程的输出在运行时与主线程的输出交错。

此外,在捕获main()而不是重新抛出它时,最好还原线程的中断的状态,如下所示:

InterruptedException

如果您想了解有关Java线程的更多信息,B​​rian Goetz的这个tutorial非常好。它是IBM developerWorks Java concurrency培训模块的一部分。

答案 3 :(得分:0)

那是一些严重混乱的代码。 OP,你没有写这个,但你只是因为磕磕绊绊而加热。

首先:NewThread不是一个线程,它是一个Runnable。不一样,也是有原因的。但是它的构造函数声明了一个新线程并且立即启动它,将Runnable变成某种Zombie Thread,这违背了在Runnable中使用Runnable的全部目的。第一个地方,这只是一个可怕的想法,因为如果你想要一个线程,你会声明一个线程,而不是一个Runnable。如果你想在ThreadPool中使用Runnable怎么办?如果您想要定义多个Runnable并以有序的方式启动它们,该怎么办?如果Runnable有一天变成Callable,你会在哪里看到它的未来呢?

然后,为了增加对伤害的侮辱,代码在主线程中具有并发代码。这个服务器没有教育目的,几乎没有现实生活价值,因为在现实生活中,你通常不会混合那样的线程代码,你宁愿有一个控制线程(主)和1..n工作线程(由主要人控制。

Threads和Runnables的意思是将任务的功能描述(即Runnable)与生命周期行为(即Thread)分开。并行执行和可伸缩性是一个很好的附带好处。因此,让我们重构教程代码以反映:

class Countdown implements Runnable {

  public void run() {
    try {
      for(int i = 5; i > 0; i--) {
        System.out.println("Child Thread: " + i);
        Thread.sleep(50);
      }
    } catch (InterruptedException e) {
      System.out.println("Child interrupted.");
    }
    System.out.println("Exiting child thread.");
  }
}

public class ThreadDemo2 {
  public static void main(String args[]) {
    Thread t = new Thread(new Countdown());
    t.start();
    try {
      for(int i = 5; i > 0; i--) {
        System.out.println("Main Thread: " + i);
        Thread.sleep(100);
      }
    } catch (InterruptedException e) {
      System.out.println("Main thread interrupted.");
    }
    System.out.println("Main thread exiting.");
  }
}

那更好。现在,Runnable不再伪装成一个Thread,也不关心它何时,如何以及由谁运行。它所做的只是实现run(),它执行任务应该做的事情,主线程将此Runnable作为新Thread的构造函数参数,然后start()s,这反过来意味着新线程将调用Runnable的run()。但是我们可以做得更好:两个线程基本上做同样的事情,所以我们应该这样实现它们:

class Countdown implements Runnable {
  final String name;
  final int length;
  final int skip;

  public Countdown(String name, int length, int skip) {
    this.name = name;
    this.length = length;
    this.skip = skip;
  }

  public void run() {
    try {
      for(int i = length; i > 0; i--) {
        System.out.println(name + ": " + i);
        Thread.sleep(skip);
      }
    } catch (InterruptedException e) {
      System.out.println(name + " interrupted.");
    }
    System.out.println("Exiting " + name);
  }
}

public class ThreadDemo3 {
  public static void main(String args[]) {
    Thread t1 = new Thread(new Countdown("Child One", 5, 50));
    Thread t2 = new Thread(new Countdown("Child Two", 5, 100));
    t1.start();
    t2.start();
  }
}

现在我们将功能与生命周期管理分开了。倒计时是它自己的类,它完全按照名称所说的而不是更多,并且主要没有更多的工作逻辑。 Main只是调用倒计时并启动它们。

OP,我最大的建议是:找一个更好的教程。上面grkvlt提到的Brian Goetz教程很多更好。您可能希望通过Goetz(“Java Concurrency in Practice”)和Doug Lea(“Java中的并行编程”)在书籍上投入一些资金。