-4

我在教程网站上找到了这段代码:

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

4 回答 4

0

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

让实现类java.lang.Runnable自己创建线程有点奇怪。查看 JavaDoc for java.lang.Thread中有关如何使用线程的示例。

于 2013-08-20T14:28:35.073 回答
0

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

于 2013-08-20T14:38:40.973 回答
0

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

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

创建一个名为Demo ThreadThread的新对象,使用它自己(的一个实例)作为任务,因为它实现了接口。然后,当被调用时,实例的方法被调用。tNewThreadRunnableRunnablet.start()run()NewThreadt

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

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

此外,当捕获InterruptedException而不是重新抛出它时,恢复线程的中断状态是一种很好的做法,如下所示:

} catch (InterruptedException ie) {
    System.out.println("Interrupted: " + ie.getMessage());
    Thread.currentThread().interrupt();
}

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

于 2013-08-20T14:42:15.813 回答
0

那是一些严重混乱的代码。OP,你没有写这个,但你会因为偶然发现它而发火。

首先:NewThread 不是线程,它是 Runnable。不是一回事,而且是有原因的。但是随后它的构造函数声明了一个新线程并立即启动它,将 Runnable 变成某种僵尸线程,这首先破坏了拥有 Runnable 的全部目的,这只是一个糟糕的主意,因为如果你想要一个线程,你会声明一个线程,而不是一个可运行的。如果你想在 ThreadPool 中使用 Runnable 怎么办?如果你想定义多个 Runnables 并以有序的方式启动它们怎么办?如果有一天 Runnable 变成了 Callable,你会在哪里看到它的 Future?

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

Threads and 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 不再假装是一个线程,它甚至也不关心它何时、如何或由谁来运行。它所做的只是实现 run() 来完成任务应该做的事情,并且主线程将此 Runnable 作为构造函数参数提供给新线程,然后 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();
  }
}

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

OP,我最大的建议是:找一个更好的教程。上面 grkvlt 提到的 Brian Goetz 教程好得多。您可能还想在 Goetz(“Java Concurrency in Practice”)和 Doug Lea(“Concurrent Programming in Java”)的书籍上投资一些钱。

于 2013-08-20T16:13:45.667 回答