【问题标题】:When I inherit from Thread, does every method in the class run on the new Thread?当我从 Thread 继承时,类中的每个方法都运行在新的 Thread 上吗?
【发布时间】:2015-12-21 21:47:27
【问题描述】:

我有一个程序,我希望每次创建它的实例时都在 new Thread 上运行一个特定的类。为此,我使用了多线程的extend Thread 继承方法。但是,我想知道的是:当我为某个类extend Thread 时,我调用的该类的每个方法(比如在构造函数中或稍后)是否会在线程上运行,或者只会在调用run() 方法在新线程上运行?

示例:

public class Entity extends Thread {
    Entity() {
       super("Bob"); 
       start();
       method2(); //will this run on the new Thread alongside the one called in run()?

    }

    public void run() {
       method1(); //will only this method run on the new Thread? 
    }

    int method1() {
         return 1;
    }

    int method2() {
         return 2;
    }

}

或:

public class World {
    public static void main(String args[]) {
        Entity example = new Entity(); 
        example.method2(); //will this run on the new Thread?

    }

}

【问题讨论】:

  • 你在尝试的时候看到了什么?
  • 我不能完全确定,我会尝试编写一个输出更明显的程序。当我添加打印语句时,导致所有数字都立即打印出来。我将尝试使用 Thread.sleep(),
  • 1-不要,您应该更喜欢使用 Runnable 并将其包装为 Thread 的实例和 2- 不,或者更重要的是,除非方法被执行从Threadrun 方法的上下文中
  • 因为您没有创建一种新的Thread(这是扩展所暗示的)。您只需要在一个代码中运行一些代码。
  • run 方法在Thread 中的事实并不意味着它在新线程上运行:它在调用它的线程上运行。例如如果您调用thread.start(),它将在一个新线程上,但如果您直接调用thread.run(),则不会。

标签: java multithreading inheritance extends java-threads


【解决方案1】:

只有调用start() 方法才能创建一个新线程。调用 run() 或您在类中定义的任何其他方法不会创建一个新线程并且仍然在当前线程上运行。

因此,使用Thread 类的正确方法是 在类外部调用构造函数和start() 方法。该类应该做的所有事情都应该适合run() 方法。


假设您有以下代码。

public class MyClass extends Thread {
    public void myMethod() {
       //implementation
    }
    public void run() {
       myMethod();
       //other implementation
    }
}
public class Application {
    public static void main(String args[]) {
       new MyClass().start();
    }
}

此代码创建MyClass 的新实例并调用其start() 方法,该方法创建一个新线程并自动在其上运行run() 方法。


相反,考虑以下代码:

public class Application {
    public static void main(String args[]) {
       new MyClass().run();
    }
}

public class Application {
    public static void main(String args[]) {
       new MyClass().myMethod();
    }
}

那些代码只在当前线程上执行方法。


所以要回答你的问题,第一个 method2() 调用不会在单独的线程上运行。如果通过start() 方法调用run()method1() 调用只会在新线程上运行。第二个method2() 调用不会在单独的线程上运行。


另外,正如另一个答案中提到的,在构造函数中调用 start() 从来都不是好习惯。

【讨论】:

    【解决方案2】:

    答案很简单,所有你想在另一个线程中运行的东西都必须在方法run()中调用。

    【讨论】:

      【解决方案3】:

      只有在实体的构造函数中调用 run 创建的新线程中才会调用从实体的 run 方法进行的 method1 调用。从 main 方法调用实体上的 method2 由主线程执行。同样start是由main方法调用的,所以Entity构造函数对method2的调用由主线程执行。

      在您的实体构造函数中,发生的情况是调用了超类的 start 方法,从而创建了一个新线程(实体对象的 run 方法将在新线程中被调用),然后当前线程继续调用方法2。不仅没有在新线程中调用method2,而且根据启动新线程所需的时间,很可能在调用method2之后可以执行Entity上的run方法(尽管没有指定首先发生的情况,任何一个线程都可以先执行)。

      您可以通过记录线程名称来测试哪个线程正在运行某些东西。使用 this.getName() 返回 Thread 对象的名称,而不是执行代码的线程的名称。您可以将实体的方法 1 和方法 2 代码更改为

      int method1() {
           System.out.println("in method1 of " + this.getName() 
           + ", executed from " + Thread.currentThread().getName());
           return 1;
      }
      
      int method2() {
           System.out.println("in method2 of " + this.getName() 
           + ", executed from " + Thread.currentThread().getName());
           return 2;
      }
      

      为了看到两者的区别,导致

      in method2 of Bob, executed from main
      in method1 of Bob, executed from Bob
      in method2 of Bob, executed from main
      

      请注意,引入 printlns 可能会改变程序线程的执行顺序。

      构造函数用于初始化你的对象;在构造函数完成之前让线程启动很容易出错,因为线程在对象完全初始化之前执行 run 方法。

      让您的实体扩展 Thread 很尴尬,原因有几个,您不能从其他任何子类化,并且您可能会意外覆盖 Thread 上的方法。通常使用可以使用线程池的执行器比让对象尝试管理它们自己的专用线程要好。如果您特别希望对象在自己的线程上运行并异步通信,您可以查看Actor model,特别是Akka

      【讨论】:

        猜你喜欢
        • 2013-11-26
        • 2012-02-24
        • 1970-01-01
        • 2012-05-02
        • 2021-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多