Java中的“实现Runnable”与“扩展线程”

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

使用implements Runnable

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

或者,使用extends Thread

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

这两个代码块有什么显着差异吗?

是的:实现Runnable是首选方法,IMO。 你并不是真正专注于线程的行为。 你只是给它一些东西来运行。 这意味着构图是哲学上 “更纯粹”的方式。

实际上 ,它意味着您可以实现Runnable并从另一个类扩展。

tl; dr:实现Runnable更好。 但是,警告很重要

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

警告:在这里,我强烈反对使用原始线程。 我更喜欢使用Callables和FutureTasks (来自javadoc:“可取消的异步计算”)。 超时,正确取消和现代并发支持的线程池的集成对我来说比成堆的原始线程更有用。

后续:有一个FutureTask构造函数 ,允许您使用Runnables(如果这是您最熟悉的),并且仍然可以获得现代并发工具的好处。 引用javadoc:

如果您不需要特定结果,请考虑使用以下forms的结构:

 Future f = new FutureTask(runnable, null) 

因此,如果我们用threadA替换他们的runnable ,我们得到以下内容:

 new FutureTask(threadA, null) 

允许您更接近Runnables的另一个选项是ThreadPoolExecutor 。 您可以使用execute方法传入Runnable以在将来某个时间执行“给定任务”。

如果您想尝试使用线程池,上面的代码片段将变为如下所示(使用Executors.newCachedThreadPool()工厂方法):

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

故事的道德启示:

仅在您要覆盖某些行为时inheritance。

或者更确切地说,它应该被理解为:

inheritance少,界面更多。

那么多好的答案,我想在此添加更多。 这将有助于理解Extending v/s Implementing Thread
Extends非常紧密地绑定两个类文件,并且可能导致一些非常难以处理的代码。

两种方法都做同样的工作,但存在一些差异。
最常见的区别是

  1. 当您扩展Thread类时,之后您无法扩展您需要的任何其他类。 (如您所知,Java不允许inheritance多个类)。
  2. 实现Runnable时,可以为类保存一个空间,以便将来或现在扩展任何其他类。

但是,实现Runnable和扩展Thread之间的一个显着区别
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.

以下示例可帮助您更清楚地理解

 //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 above 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接口方法中,只创建了一个类的一个实例,并且它已由不同的线程共享。 因此,对于每个线程访问,计数器的值都会递增。

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

什么时候使用Runnable?
如果要从线程组访问相同的资源,请使用Runnable接口。 避免在这里使用Thread类,因为多个对象创建会占用更多内存,并且会成为很大的性能开销。

实现Runnable的类不是一个线程而只是一个类。 要使Runnable成为线程,您需要创建一个Thread实例并将其自身作为目标传递。

在大多数情况下,如果您只计划覆盖run()方法而不使用其他Thread方法,则应使用Runnable接口。 这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应对类进行子类化。

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

我希望这个能帮上忙!

我还没有提到的一件事是,实现Runnable会让你的课程变得更加灵活。

如果你扩展线程,那么你正在做的动作总是在一个线程中。 但是,如果您实现Runnable ,则不必如此。 您可以在一个线程中运行它,或者将它传递给某种执行器服务,或者只是作为单个线程应用程序中的任务传递它(可能在以后运行,但在同一个线程内)。 如果你只使用Runnable ,那么这些选项会比将你自己绑定到Thread更加开放。

如果你想实现或扩展任何其他类,那么如果你不希望任何其他类扩展或实现那么Runnable接口是最优选的,那么Thread类是更可取的

最常见的区别是

在此处输入图像描述

当您extends Thread类时,之后您无法扩展您需要的任何其他类。 (如您所知,Java不允许inheritance多个类)。

implements Runnable ,可以为类保存一个空间,以便将来或现在扩展任何其他类。

  • Java不支持多重inheritance,这意味着你只能在Java中扩展一个类,所以一旦你扩展了Thread类,你就失去了机会,无法在Java中扩展或inheritance另一个类。

  • 在面向对象的编程中,扩展类通常意味着添加新function,修改或改进行为。 如果我们不在Thread上进行任何修改,那么请改用Runnable接口。

  • Runnable接口表示一个Task,它可以由普通的Thread或Executor或任何其他方法执行。 所以将Task作为Runnable与Thread进行逻辑分离是一个很好的设计决策。

  • 将任务分离为Runnable意味着我们可以重用该任务,并且可以自由地从不同的方式执行它。 因为一旦完成就无法重启线程。 再次Runnable vs Thread for task,Runnable是胜利者。

  • Java设计者认识到这一点,这就是Executors接受Runnable作为Task的原因,他们有工作线程来执行这些任务。

  • inheritance所有Thread方法只是用于表示可以使用Runnable轻松完成的Task的额外开销。

礼貌来自javarevisited.blogspot.com

这些是Java中Thread和Runnable之间的一些显着差异,如果你知道Thread vs Runnable上的任何其他差异,请通过评论分享。 我个人在这种情况下使用Runnable over Thread,并建议根据您的要求使用Runnable或Callable接口。

但是,显着的区别是。

当您extends Thread类时,每个线程都会创建唯一对象并与之关联。 implements Runnable ,它将同一对象共享给多个线程。

实际上,将RunnableThread相互比较是不明智的。

这两者在multithreading中具有依赖性和关系,就像机动车的Wheel and Engine关系一样。

我想说,只有一种方法可以通过两个步骤实现multithreading。 让我说明我的观点。

可运行:
实现interface Runnable ,意味着您正在创建可在不同线程中run able东西。 现在创建可以在线程内运行的东西(在线程内可运行)并不意味着创建一个Thread。
所以MyRunnableMyRunnable是一个带有void run方法的普通类。 它的对象将是一些普通对象,只有一个方法run ,在调用时将正常执行。 (除非我们在一个线程中传递对象)。

线:
class Thread ,我会说一个非常特殊的类,能够启动一个新的Thread,它实际上通过start()方法实现multithreading。

为什么不明智地比较?
因为我们需要它们用于multithreading。

对于multithreading,我们需要两件事:

  • 可以在Thread(Runnable)中运行的东西。
  • 可以启动新线程(线程)的东西。

因此从技术上和理论上讲,它们都是启动螺纹所必需的,一个将运行 ,一个将使其运行 (如机动车的Wheel and Engine )。

这就是为什么你不能用MyRunnable启动一个线程,你需要将它传递给一个Thread实例。

但是有可能只使用class Thread来创建和运行一个线程,因为Class Thread实现了Runnable所以我们都知道Thread也是一个Runnable

最后, ThreadRunnable是multithreading而不是竞争对手或替代者的补充。

您应该实现Runnable,但是如果您在Java 5或更高版本上运行,则不应该使用new Thread启动它,而是使用ExecutorService 。 有关详细信息,请参阅: 如何在Java中实现简单线程 。

我不是专家,但我可以想到实现Runnable而不是扩展Thread的一个原因:Java只支持单inheritance,所以你只能扩展一个类。

编辑:这最初说“实现一个接口需要更少的资源。” 同样,但你需要创建一个新的Thread实例,所以这是错误的。

我想说还有第三种方式:

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

也许这有点受到我最近大量使用Javascript和Actionscript 3的影响,但是这样你的类不需要像Runnable那样实现一个非常模糊的界面。

随着Java 8的发布,现在有第三种选择。

Runnable是一个function接口 ,这意味着可以使用lambda表达式或方法引用创建它的实例。

您的示例可以替换为:

 new Thread(() -> { /* Code here */ }).start() 

或者如果要使用ExecutorService和方法引用:

 executor.execute(runner::run) 

这些不仅比您的示例短得多,而且还具有使用Runnable over Thread其他答案中陈述的许多优点,例如单一责任和使用组合,因为您没有专门化线程的行为。 如果你需要的只是一个Runnable就像在你的例子中一样,这种方式也避免了创建一个额外的类。

实例化接口可以在代码和线程实现之间实现更清晰的分离,因此在这种情况下我更愿意实现Runnable。

  1. Java不支持多重inheritance,这意味着你只能在Java中扩展一个类,所以一旦你扩展了Thread类,你就失去了机会,无法在Java中扩展或inheritance另一个类。
  2. 在面向对象的编程中,扩展类通常意味着添加新function,修改或改进行为。 如果我们不在Thread上进行任何修改而不是使用Runnable接口。
  3. Runnable接口表示一个Task ,它可以由普通的ThreadExecutors或任何其他方法执行。 因此,将Task作为RunnableThread逻辑分离是一个很好的设计决策。
  4. 将任务分离为Runnable意味着我们可以重用该任务,并且可以自由地从不同的方式执行它。 由于一旦完成就无法重新启动Thread ,再次运行Runnable vs Thread任务, Runnable就是胜利者。
  5. Java设计者认识到这一点,这就是Executors接受Runnable作为Task的原因,他们有工作线程来执行这些任务。
  6. inheritance所有Thread方法只是用于表示可以使用Runnable轻松完成的Task额外开销。

Runnable因为:

  • 为Runnable实现提供了更大的灵活性来扩展另一个类
  • 将代码与执行分开
  • 允许您从线程池,事件线程或将来以任何其他方式运行runnable。

即使你现在不需要这些,也可能在未来。 由于重写Thread没有任何好处,Runnable是一个更好的解决方案。

这里的每个人似乎认为实现Runnable是要走的路,我并不是真的不同意它们,但在我看来还有一个扩展Thread的案例,事实上你已经在你的代码中展示了它。

如果实现Runnable,那么实现Runnable的类无法控制线程名称,它是可以设置线程名称的调用代码,如下所示:

 new Thread(myRunnable,"WhateverNameiFeelLike"); 

但是如果你扩展Thread然后你就可以在类本身内管理它(就像在你的例子中你命名线程’ThreadB’)。 在这种情况下你:

A)可能会为调试目的提供一个更有用的名称

B)强制该名称用于该类的所有实例(除非你忽略它是一个线程并使用它执行上面的操作,就好像它是一个Runnable但我们在这里谈论约定,所以可以忽略我觉得的那种可能性)。

您甚至可以例如获取其创建的堆栈跟踪并将其用作线程名称。 这可能看起来很奇怪,但根据代码的结构,它对调试非常有用。

这可能看起来像一个小东西,但你有一个非常复杂的应用程序,有很multithreading,突然之间“已经停止”(出于死锁的原因,或者可能是因为网络协议中的缺陷会少一些显然 – 或其他无限的原因)然后从Java获得堆栈转储,其中所有线程被称为’Thread-1’,’Thread-2’,’Thread-3’并不总是非常有用(它取决于你的线程如何结构化以及是否可以通过堆栈跟踪有用地告诉哪个是哪个 – 如果您使用的是多个线程的组都运行相同的代码,则不总是可行的。

说过你当然也可以通过创建一个线程类的扩展来以一般方式完成上述操作,该线程类将其名称设置为其创建调用的堆栈跟踪,然后将其与Runnable实现而不是标准java Thread类一起使用(参见下文)但除了堆栈跟踪之外,可能还有更多特定于上下文的信息,这些信息在调试的线程名称中很有用(对可以处理的许多队列或套接字之一的引用,例如在这种情况下您可能更喜欢特别针对该情况扩展Thread,以便您可以让编译器强制您(或其他使用您的库)传递某些信息(例如,有问题的队列/套接字)以便在名称中使用)。

以下是调用堆栈跟踪作为其名称的通用线程的示例:

 public class DebuggableThread extends Thread { private static String getStackTrace(String name) { Throwable t= new Throwable("DebuggableThread-"+name); ByteArrayOutputStream os = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(os); t.printStackTrace(ps); return os.toString(); } public DebuggableThread(String name) { super(getStackTrace(name)); } public static void main(String[] args) throws Exception { System.out.println(new Thread()); System.out.println(new DebuggableThread("MainTest")); } } 

这是一个比较两个名称的输出样本:

 Thread[Thread-1,5,main] Thread[java.lang.Throwable: DebuggableThread-MainTest at DebuggableThread.getStackTrace(DebuggableThread.java:6) at DebuggableThread.(DebuggableThread.java:14) at DebuggableThread.main(DebuggableThread.java:19) ,5,main] 

由于这是一个非常受欢迎的话题,而且好的答案遍布各处并深入处理,我觉得将其他人的好答案汇编成更简洁的forms是合理的,因此新人有一个简单的概述:

  1. 您通常会扩展一个类来添加或修改function。 因此, 如果您不想 覆盖任何Thread行为 ,请使用Runnable。

  2. 同样, 如果您不需要 inheritance线程方法,那么使用Runnable可以避免这种开销

  3. 单inheritance :如果扩展Thread,则无法从任何其他类扩展,因此如果您需要这样做,则必须使用Runnable。

  4. It is good design to separate domain logic from technical means, in that sense it is better to have a Runnable task isolating your task from your runner .

  5. You can execute the same Runnable object multiple times , a Thread object, however, can only be started once. (Maybe the reason, why Executors do accept Runnables, but not Threads.)

  6. If you develop your task as Runnable, you have all flexibility how to use it now and in the future . You can have it run concurrently via Executors but also via Thread. And you still could also use/call it non-concurrently within the same thread just as any other ordinary type/object.

  7. This makes it also easier to separate task-logic and concurrency aspects in your unit tests .

  8. If you are interested in this question, you might be also interested in the difference between Callable and Runnable .

This is discussed in Oracle’s Defining and Starting a Thread tutorial:

Which of these idioms should you use? The first idiom, which employs a Runnable object, is more general, because the Runnable object can subclass a class other than Thread. The second idiom is easier to use in simple applications, but is limited by the fact that your task class must be a descendant of Thread. This lesson focuses on the first approach, which separates the Runnable task from the Thread object that executes the task. Not only is this approach more flexible, but it is applicable to the high-level thread management APIs covered later.

In other words, implementing Runnable will work in scenarios where your class extends a class other than Thread . Java does not support multiple inheritance. Also, extending Thread will not be possible when using some of the high-level thread management APIs. The only scenario where extending Thread is preferable is in a small application that won’t be subject to updates in future. It is almost always better to implement Runnable as it is more flexible as your project grows. A design change won’t have a major impact as you can implement many interfaces in java, but only extend one class.

If I am not wrong, it’s more or less similar to

What is the difference between an interface and abstract class?

extends establishes ” Is A ” relation & interface provides ” Has a ” capability.

Prefer implements Runnable :

  1. If you don’t have to extend Thread class and modify Thread API default implementation
  2. If you are executing a fire and forget command
  3. If You are already extending another class

Prefer ” extends Thread ” :

  1. If you have to override any of these Thread methods as listed in oracle documentation page

Generally you don’t need to override Thread behaviour. So implements Runnable is preferred for most of the times.

On a different note, using advanced ExecutorService or ThreadPoolExecutorService API provides more flexibility and control.

Have a look at this SE Question:

ExecutorService vs Casual Thread Spawner

Difference between Extending Thread and Implementing Runnable are:

在此处输入图像描述

Separating the Thread class from the Runnable implementation also avoids potential synchronization problems between the thread and the run() method. A separate Runnable generally gives greater flexibility in the way that runnable code is referenced and executed.

One reason you’d want to implement an interface rather than extend a base class is that you are already extending some other class. You can only extend one class, but you can implement any number of interfaces.

If you extend Thread, you’re basically preventing your logic to be executed by any other thread than ‘this’. If you only want some thread to execute your logic, it’s better to just implement Runnable.

if you use runnable you can save the space to extend to any of your other class.

Can we re-visit the basic reason we wanted our class to behave as a Thread ? There is no reason at all, we just wanted to execute a task, most likely in an asynchronous mode, which precisely means that the execution of the task must branch from our main thread and the main thread if finishes early, may or may not wait for the branched path(task).

If this is the whole purpose, then where do I see the need of a specialized Thread. This can be accomplished by picking up a RAW Thread from the System’s Thread Pool and assigning it our task (may be an instance of our class) and that is it.

So let us obey the OOPs concept and write a class of the type we need. There are many ways to do things, doing it in the right way matters.

We need a task, so write a task definition which can be run on a Thread. So use Runnable.

Always remember implements is specially used to impart a behaviour and extends is used to impart a feature/property.

We do not want the thread’s property, instead we want our class to behave as a task which can be run.

Yes, If you call ThreadA call , then not need to call the start method and run method is call after call the ThreadA class only. But If use the ThreadB call then need to necessary the start thread for call run method. If you have any more help, reply me.

I find it is most useful to use Runnable for all the reasons mentioned, but sometimes I like to extend Thread so I can create my own thread stopping method and call it directly on the thread I have created.

Java does not support multiple inheritence so if you extends Thread class then no other class will be extended.

For Example: If you create an applet then it must extends Applet class so here the only way to create thread is by implementing Runnable interface

That’s the S of SOLID : Single responsibility.

A thread embodies the running context (as in execution context: stack frame, thread id, etc.) of the asynchronous execution of a piece of code. That piece of code ideally should be the same implementation, whether synchronous or asynchronous .

If you bundle them together in one implementation, you give the resulting object two unrelated causes of change:

  1. thread handling in your application (ie. querying and modifying the execution context)
  2. algorithm implemented by the piece of code (the runnable part)

If the language you use supports partial classes or multiple inheritance, then you can segregate each cause in its own super class, but it boils down to the same as composing the two objects, since their feature sets don’t overlap. That’s for the theory.

In practice, generally speaking, a programme does not need to carry more complexity than necessary. If you have one thread working on a specific task, without ever changing that task, there is probably no point in making the tasks separate classes, and your code remains simpler.

In the context of Java , since the facility is already there , it is probably easier to start directly with stand alone Runnable classes, and pass their instances to Thread (or Executor ) instances. Once used to that pattern, it is not harder to use (or even read) than the simple runnable thread case.

Difference between Thread and runnable .If we are creating Thread using Thread class then Number of thread equal to number of object we created . If we are creating thread by implementing the runnable interface then we can use single object for creating multiple thread.So single object is shared by multiple Thread.So it will take less memory

So depending upon the requirement if our data is not senstive. So It can be shared between multiple Thread we can used Runnable interface.

Adding my two cents here – Always whenever possible use implements Runnable . Below are two caveats on why you should not use extends Thread s

  1. Ideally you should never extend the Thread class; the Thread class should be made final . At least its methods like thread.getId() . See this discussion for a bug related to extending Thread s.

  2. Those who like to solve puzzles can see another side effect of extending Thread. The below code will print unreachable code when nobody is notifying them.

Please see http://pastebin.com/BjKNNs2G .

 public class WaitPuzzle { public static void main(String[] args) throws InterruptedException { DoNothing doNothing = new DoNothing(); new WaitForever(doNothing).start(); new WaitForever(doNothing).start(); new WaitForever(doNothing).start(); Thread.sleep(100); doNothing.start(); while(true) { Thread.sleep(10); } } static class WaitForever extends Thread { private DoNothing doNothing; public WaitForever(DoNothing doNothing) { this.doNothing = doNothing; } @Override public void run() { synchronized (doNothing) { try { doNothing.wait(); // will wait forever here as nobody notifies here } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Unreachable Code"); } } } static class DoNothing extends Thread { @Override public void run() { System.out.println("Do Nothing "); } } } 

One difference between implementing Runnable and extending Thread is that 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.

A class that implements Runnable is not a thread and just a class. For a Runnable to be executed by a Thread, you need to create an instance of Thread and pass the Runnable instance in as the target.

In most cases, the Runnable interface should be used if you are only planning to override the run() method and no other Thread methods. This is important because classes should not be subclassed unless the programmer intends on modifying or enhancing the fundamental behavior of the class.

When there is a need to extend a superclass, implementing the Runnable interface is more appropriate than using the Thread class. Because we can extend another class while implementing Runnable interface to make a thread. But if we just extend the Thread class we can’t inherit from any other class.