当我从Thread继承时,类中的每个方法都在新的Thread上运行吗?

时间:2015-12-21 21:47:28

标签: java multithreading inheritance extends java-threads

我有一个程序,我想在每次创建它的实例时在new Thread上运行一个特定的类。为此,我使用多线程的extend Thread继承方法。但是,我想知道的是:当我extend Thread为某个类时,我调用的那个类的每个方法(比如在构造函数中或以后)都会在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?

    }

}

3 个答案:

答案 0 :(得分: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()调用将不会在单独的线程上运行。如果通过method1()方法调用run()start()调用将仅在新主题上运行。第二个method2()调用不会在单独的线程上运行。

另外,正如其他答案中所提到的,在构造函数中调用start()绝不是一种好习惯。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

您可以通过记录线程名称来测试正在运行的线程。使用this.getName()返回Thread对象的名称,而不是执行代码的线程的名称。您可以将实体的method1和method2代码更改为

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的方法的风险。通常使用可以使用线程池的执行程序比让对象尝试管理自己的专用线程更好。如果您特别希望对象在自己的线程上运行并以异步方式进行通信,则可以查看Actor model,特别是Akka