java - “implements Runnable” VS “extends Thread”

  显示原文与译文双语对照的内容

从我在Java中使用线程的时间来看,我发现了两种编写线程的方法:

使用 implements Runnable:


public class ThreadA implements Runnable {
 public void run() {
//Code
 }
}
//Started with a"new Thread(threadA).start()" call

或者,使用 extends Thread:


public class ThreadB extends Thread {
 public ThreadB() {
 super("ThreadB");
 }
 public void run() {
//Code
 }
}
//Started with a"threadB.start()" call

这两个代码块有显著差异?

时间:

是:实现 Runnable 是实现它的首选方式,IMO 。 你并不是真正的专注于线程的行为。 你只是想让它运行。 这意味着组合是的philosophically 。

在另一个类作为 well, 实用术语中,它意味着你可以实现 Runnable 和 extend.

的tl ;dr: 实现Runnable更好。 然而,警告是重要的

通常,我建议使用像 Runnable 而不是 Thread 这样的东西,因为它允许你保持工作的松散耦合和你选择的并发性。 例如如果你使用 Runnable 并稍后决定这实际上不需要它自己的Thread,你可以只调用 threadA.run() 。

这里要警告 在转角,我强烈不鼓励的使用原始的线程。 我更喜欢使用 CallablesFutureTasks ( 来自 javadoc: "可以取消的异步计算") 。现代并发支持的集成,适当的取消以及现代并发支持的线程池对我来说比原始的线程更有用。

花费了的时间: 有一个 FutureTask 构造函数,它允许你使用 Runnables ( 如果这是你最喜欢的),并仍然可以获得现代并发工具的好处。 引用 javadoc:

如果不需要特定的结果,请考虑使用表单的结构:


Future<?> f = new FutureTask<Object>(runnable, null)

你的threadA following,,我们得到的就是,如果我们把他们


new FutureTask<Object>(threadA, null)

允许你靠近Runnables的另一个选项是 ThreadPoolExecutor 。 你可以使用执行方法来传递 Runnable,以便在将来执行给定的任务。"

如果你想使用一个线程池,上面的代码Fragment将变成如下( 使用 Executors.newCachedThreadPool() 工厂方法):


ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());

好的,好的答案,我想添加更多,这将有助于理解 Extending v/s Implementing Thread_
扩展两个类文件非常紧密,并且可能导致一些代码难以处理。

两种方法都做了同样的工作,但有一些不同。
最常见的区别是

  1. 当你扩展Thread类时,你不能扩展任何需要的其他类。 ( 就像你所知道的,Java不允许继承多个类) 。
  2. 当你实现Runnable时,你可以为你的类节省一个空间,以便将来或者现在扩展其他类。

实现可以运行和扩展线程之间 但是,一个显著的区别是,
by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance.

下面的示例来帮助你了解更多 clearly_


//Implement Runnable Interface...
 class ImplementsRunnable implements Runnable {

private int counter = 0;

public void run() {
 counter++;
 System.out.println("ImplementsRunnable : Counter :" + counter);
 }
}

//Extend Thread class...
class ExtendsThread extends Thread {

private int counter = 0;

public void run() {
 counter++;
 System.out.println("ExtendsThread : Counter :" + counter);
 }
}

//Use 上面 classes here in main to understand the differences more clearly...
public class ThreadVsRunnable {

public static void main(String args[]) throws Exception {
//Multiple threads share the same object.
 ImplementsRunnable rc = new ImplementsRunnable();
 Thread t1 = new Thread(rc);
 t1.start();
 Thread.sleep(1000);//Waiting for 1 second before starting next thread
 Thread t2 = new Thread(rc);
 t2.start();
 Thread.sleep(1000);//Waiting for 1 second before starting next thread
 Thread t3 = new Thread(rc);
 t3.start();

//Creating new instance for every thread access.
 ExtendsThread tc1 = new ExtendsThread();
 tc1.start();
 Thread.sleep(1000);//Waiting for 1 second before starting next thread
 ExtendsThread tc2 = new ExtendsThread();
 tc2.start();
 Thread.sleep(1000);//Waiting for 1 second before starting next thread
 ExtendsThread tc3 = new ExtendsThread();
 tc3.start();
 }
}

上述程序的输出。


ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

在Runnable接口方法中,只创建了一个类的一个实例,它被不同的线程共享。 因此,每个线程访问的计数器值递增。

然而,线程类方法,必须为每个线程访问创建单独的实例。 因此为每个类实例分配了不同的内存,每个实例都有单独的计数器,该值保持不变,这意味着不会发生增量,因为没有一个对象引用相同。

使用Runnable时的?
当你想从线程组访问相同的资源时使用Runnable接口。 避免在这里使用线程类,因为多个对象创建消耗了更多内存,并且它成为一个巨大的性能开销。


A class that implements Runnable is not a thread and just a class. For a Runnable to become a Thread, You need to create an instance of Thread and passing itself in as the target.

在大多数情况下,如果只计划重写 run() 方法而没有其他线程方法,则应该使用Runnable接口。 这很重要,因为除非程序员打算修改或者增强类的基本行为,否则类不应该是子类。

当需要扩展超类时,实现Runnable接口比使用Thread类更合适。 因为我们可以在实现Runnable接口时扩展另一个类来创建一个线程。

我希望这会帮助你 !

如果你想实现或者扩展任何其他类,那么 Runnable 接口是最好的其他方法,如果你不希望其他任何类扩展或者实现,那么 Thread 类就更好了

最常见的区别是

enter image description here

extends Thread 类中,你不能扩展任何需要的其他类。 ( 就像你所知道的,Java不允许继承多个类) 。

当你 implements Runnable 时,你可以为你的类节省一个空间,以便将来或者现在扩展其他类。

  • Java不支持多重继承,这意味着你只能在Java中扩展一个类,因此一旦你扩展了Thread类,就不能在Java中扩展或者继承另一个类。

  • 在面向对象的程序设计中,扩展一个类通常意味着添加新的功能,修改或者改进行为。 如果我们没有对线程进行任何修改而不是使用Runnable接口。

  • 可以运行接口代表一个可以由普通线程或者执行器执行的任务,或者任何其他方法。 因此,将任务作为可以运行的线程进行逻辑分离是好的设计决策。

  • 将任务分离为Runnable意味着我们可以重用任务,也可以自由地从不同的方式执行它。 因为你不能在线程完成后重新启动它。 再次运行的vs 线程任务,Runnable是赢家。

  • Java设计器认识到这一点,这就是为什么执行器接受Runnable作为任务,并且他们拥有执行这些任务的工作线程。

  • 继承所有线程方法只是表示一个任务的额外开销,它可以轻松地使用 Runnable 。

来自 javarevisited.blogspot.com的Courtesy

如果你知道线程 vs 可以运行的其他区别,那么在Java中线程和Runnable之间的差异就会显著。 我个人针对这个场景使用 Runnable,建议使用基于你的需求的可以运行接口或者可以调用接口。

然而,的差异是。

extends Thread 类中,每个线程都创建惟一的对象并与之关联。 当你 implements Runnable 时,它将同一个对象与多个线程共享。

new Thread 但使用一个 ExecutorService instead,应该将实现可以运行,但是当你运行在 Java 5或者更高,你不应该发动。 有关详细信息,请参阅:如何在 Java 中实现简单线程。

我认为还有第三种方法:


public class Something {

 public void justAnotherMethod() {.. . }

}

new Thread(new Runnable() {
 public void run() {
 instanceOfSomething.justAnotherMethod();
 }
}).start();

也许这受到我最近大量使用Javascript和 Actionscript 3的影响,但是这种方式你的类不需要实现一个非常模糊的界面,比如 Runnable

...