“实现可运行”与“扩展线程”
从我用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
因为它允许你保持你的工作只与你select的并发性松散耦合。 例如,如果您使用Runnable
并稍后决定实际上并不需要它自己的Thread
,则可以调用threadA.run()。
警告:在这里,我强烈build议不要使用原始线程。 我更喜欢使用Callables和FutureTasks (从javadoc:“一个可取消的asynchronous计算”)。 超时,适当的取消和现代并发支持的线程池的集成对于我来说比成堆的原始线程更有用。
后续:有一个FutureTask
构造函数 ,允许你使用Runnables(如果这是你最熟悉的),仍然可以得到现代并发工具的好处。 引用javadoc:
如果您不需要特定的结果,请考虑使用表单的结构:
Future<?> f = new FutureTask<Object>(runnable, null)
所以,如果我们用您的threadA
replace它们的runnable
,我们得到以下结果:
new FutureTask<Object>(threadA, null)
另一个允许您更接近Runnables的选项是一个ThreadPoolExecutor 。 您可以使用execute方法来传递一个Runnable来执行“将来某个时候给定的任务”。
如果你想尝试使用线程池,上面的代码片段将变成如下所示(使用Executors.newCachedThreadPool()工厂方法):
ExecutorService es = Executors.newCachedThreadPool(); es.execute(new ThreadA());
故事的道德启示:
仅当您想要覆盖某些行为时才inheritance。
或者更确切地说,它应该被理解为:
inheritanceless,接口多。
那么多好的答案,我想在这添加更多。 这将有助于了解Extending v/s Implementing Thread
。
Extends绑定两个类文件非常密切,可能会导致一些很难处理代码。
两种方法做同样的工作,但有一些差异。
最常见的区别是
- 当你扩展Thread类的时候,你不能扩展任何你需要的类。 (如您所知,Java不允许inheritance多个类)。
- 当您实现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接口方法中,只有一个类的实例正在被创build,并且被不同的线程共享。 所以计数器的值是增加每个线程访问。
而Thread类方法则必须为每个线程访问创build单独的实例。 因此,为每个类实例分配不同的内存,并且每个具有不同的计数器,值保持相同,这意味着没有增量会发生,因为没有任何对象引用是相同的。
何时使用Runnable?
当您想要从一组线程访问相同的资源时使用Runnable接口。 避免在这里使用Thread类,因为创build多个对象会消耗更多的内存,并且会成为一个很大的性能开销。
一个实现Runnable的类不是一个线程,而只是一个类。 对于一个Runnable成为一个线程,您需要创build一个线程的实例并将其作为目标传入。
在大多数情况下,如果您只打算覆盖run()
方法而没有其他Thread方法,则应该使用Runnable接口。 这很重要,因为除非程序员打算修改或增强类的基本行为,否则类不应该被分类。
当需要扩展超类时,实现Runnable接口比使用Thread类更合适。 因为我们可以在实现Runnable接口的同时扩展另一个类来创build一个线程。
我希望这会有所帮助!
有一件我感到惊讶的事情还没有被提及,那就是实现Runnable
使得你的类更加灵活。
如果你扩展线程,那么你正在做的动作总是在一个线程中。 但是,如果您实现Runnable
,则不必这样做。 您可以在一个线程中运行它,或者将它传递给某种执行器服务,或者将它作为一个任务传递给单个线程应用程序(也许稍后运行,但在同一个线程中)。 如果你只是使用Runnable
,那么这个选项比你将自己绑定到Thread
要多得多。
如果你想实现或扩展任何其他类,那么Runnable
接口是最好的其他方式,如果你不希望任何其他类扩展或实现,那么Thread
类是最好的
最常见的区别是
当你extends Thread
类的时候,你不能扩展你需要的任何其他类。 (如您所知,Java不允许inheritance多个类)。
当您implements Runnable
,您可以为您的课程节省一个空间,以便将来或现在扩展任何其他课程。
-
Java不支持多inheritance,这意味着只能扩展Java中的一个类,所以一旦扩展了Thread类,就失去了机会,无法扩展或inheritanceJava中的另一个类。
-
在面向对象编程中,扩展一个类通常意味着增加新的function,修改或改进行为。 如果我们没有对Thread进行任何修改,那么请使用Runnable接口。
-
Runnable接口表示一个任务,可以通过纯线程或执行程序或任何其他方式执行。 所以像Runnable这样的Task比逻辑分离是好的devise决策。
-
将任务分离为Runnable意味着我们可以重用任务,也可以自由地从不同的方式执行任务。 因为一旦完成,就无法重新启动线程。 再次Runnable与线程的任务,Runnable是赢家。
-
Javadevise者认识到这一点,这就是为什么执行者接受Runnable作为任务,他们有工作线程执行这些任务。
-
inheritance所有的Thread方法是额外的开销,只是为了表示一个可以使用Runnable轻松完成的任务。
礼貌来自javarevisited.blogspot.com
这些是Java中的Thread和Runnable之间的一些明显的区别,如果你知道Thread vs Runnable的其他区别,请通过注释分享。 我个人在这个场景中使用Runnable over Thread,并build议根据您的要求使用Runnable或Callable接口。
但是,显着的区别是。
extends Thread
类时,每个线程都会创build唯一的对象并与其关联。 当您implements Runnable
,它将共享同一个对象到多个线程。
实际上,将Runnable
和Thread
相互比较并不明智。
这两者就像汽车的Wheel and Engine
关系一样,在multithreading中具有依赖关系。
我想说,multithreading只有两个步骤。 让我指出我的观点。
可运行:
当实现interface Runnable
这意味着你正在创build一个run able
在不同线程中run able
东西。 现在创build一个可以在一个线程内运行的东西(可以在一个线程内运行),并不意味着创build一个线程。
所以MyRunnable
类就是一个普通的类,它有一个void run
方法。 它的对象将是一些只有一个方法run
普通对象,当调用时它将正常执行。 (除非我们在线程中传递对象)。
线:
class Thread
,我会说一个非常特殊的类,具有启动一个新的线程的能力,它实际上启用了通过它的start()
方法的multithreading。
为什么不明智比较?
因为我们需要这两者来进行multithreading。
对于multithreading,我们需要两件事:
- 可以在线程(Runnable)内运行的东西。
- 一些可以开始一个新的线程(线程)。
所以在技术上和理论上都需要启动一个线程,一个运行 ,一个运行 (像机动车辆的Wheel and Engine
)。
这就是为什么你不能用MyRunnable
启动一个线程,你需要把它传递给Thread
一个实例。
但是只能使用class Thread
来创build和运行一个线程,因为Class Thread
实现了Runnable
所以我们都知道Thread
也是一个Runnable
里面。
最后Thread
和Runnable
是互补的multithreading而不是竞争对手或替代品。
您应该实现Runnable,但是如果您运行的是Java 5或更高版本,则不应该使用new Thread
启动它,而是使用ExecutorService 。 有关详细信息,请参阅: 如何在Java中实现简单的线程 。
我不是专家,但我可以想到实现Runnable的一个原因,而不是扩展Thread:Java只支持单一inheritance,所以你只能扩展一个类。
编辑:这最初说“实现一个接口需要更less的资源”。 同样,但是你需要创build一个新的Thread实例,所以这是错误的。
我会说有第三种方法:
public class Something { public void justAnotherMethod() { ... } } new Thread(new Runnable() { public void run() { instanceOfSomething.justAnotherMethod(); } }).start();
也许这受到我最近使用JavaScript和ActionScript 3的影响,但是这样你的类不需要实现像Runnable
这样非常模糊的接口。
随着Java 8的发布,现在有了第三种select。
Runnable
是一个function接口 ,这意味着它的实例可以使用lambdaexpression式或方法引用来创build。
您的示例可以replace为:
new Thread(() -> { /* Code here */ }).start()
或者如果你想使用一个ExecutorService
和一个方法引用:
executor.execute(runner::run)
这些不仅比您的示例短得多,而且在使用Runnable
over Thread
其他答案中还提到了许多优点,例如单个责任和使用组合,因为您没有专门处理线程的行为。 这种方式也可以避免创build一个额外的类,如果你所需要的只是一个Runnable
就像你在例子中做的那样。
实例化一个接口给你的代码和线程的实现提供了一个更清晰的分离,所以我宁愿在这种情况下实现Runnable。
可运行的原因是:
- 为Runnable实现留出更多的灵活性来扩展另一个类
- 将代码与执行分离
- 允许您从线程池,事件线程或将来以任何其他方式运行您的runnable。
即使你现在不需要这些,你也可以在将来。 由于重写Thread没有任何好处,Runnable是更好的解决scheme。
这里的每个人似乎都认为实现Runnable是一条路,我并不认同它们,但是在我看来,扩展Thread也是一个例子,实际上你已经在代码中展示了它。
如果你实现了Runnable,那么实现Runnable的类就不能控制线程的名字了,它就是可以设置线程名称的调用代码,如下所示:
new Thread(myRunnable,"WhateverNameiFeelLike");
但是如果你扩展线程,那么你可以在类本身中进行pipe理(就像在你的例子中,你把线程命名为ThreadB)。 在这种情况下你:
A)可能会给它一个更有用的名称用于debugging目的
B)强迫这个名字被用于该类的所有实例(除非你忽略了它是一个线程的事实,并且把它作为一个Runnable来进行,但是我们在这里讨论的是约定忽略我感觉到的可能性)。
你甚至可以举个例子来创build它的堆栈跟踪,并将其用作线程名称。 这可能看起来很奇怪,但是根据你的代码的结构,这对于debugging的目的是非常有用的。
这可能看起来像一个小事情,但是你有一个非常复杂的应用程序,有很多的线程,突然之间的事情“已经停止”(无论是由于死锁的原因,或者可能是因为networking协议的缺陷,会less一些显而易见的 – 或其他无休止的原因),然后从所有线程被称为“线程1”,“线程2”,“线程3”Java的堆栈转储并不总是非常有用(这取决于你的线程是如何结构化和是否可以有用地告诉哪个是哪个只是他们的堆栈跟踪 – 如果你使用多个线程组都运行相同的代码,并不总是可能的)。
话虽如此,你当然也可以通过创build一个线程类的扩展,它的名称创build调用的堆栈跟踪,然后用你的Runnable实现,而不是标准的Java Thread类(见下文),但是除了堆栈跟踪之外,还可能有更多的上下文特定信息,这些信息在debugging的线程名称中很有用(对许多队列或套接字之一的引用,例如,在这种情况下,您可能更喜欢扩展线程专门为这种情况,这样你可以让你的编译器(或其他人使用你的库)传递在某些信息(例如队列/套接字问题)在名称中使用)。
下面是以调用堆栈跟踪作为其名称的通用线程示例:
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.<init>(DebuggableThread.java:14) at DebuggableThread.main(DebuggableThread.java:19) ,5,main]
由于这是一个非常受欢迎的话题,所以好的答案遍布全国,并且深入处理,我觉得把他人的好答复编成一个更简洁的forms是合理的,所以新人有一个简单的概述:
-
您通常扩展一个类来添加或修改function。 因此, 如果您不想 覆盖任何线程行为 ,请使用Runnable。
-
同样的道理, 如果你不需要 inheritance线程方法,那么你可以通过使用Runnable来避免这种开销 。
-
单inheritance :如果扩展了Thread,则不能从任何其他类扩展,所以如果这是您需要执行的操作,则必须使用Runnable。
-
将领域逻辑与技术手段分离是一个很好的devise,从这个意义上说,最好有一个Runnable任务, 将您的任务与 跑步者 隔离开来 。
-
您可以多次 执行相同的Runnable 对象 ,但是一个Thread对象只能启动一次。 (也许原因,为什么执行者确实接受Runnables,而不是Threads。)
-
如果您将任务作为Runnable进行开发,那么您现在和将来都可以灵活地使用它 。 您可以通过执行程序同时运行,也可以通过线程运行。 而且你仍然可以在同一个线程中非同时使用/调用它,就像任何其他普通的types/对象一样。
-
这使得在 unit testing中更容易分离任务逻辑和并发方面 。
-
如果您对此问题感兴趣,您可能也对Callable和Runnable之间的区别感兴趣。
这在Oracle的“ 定义和启动线程”教程中进行了讨论:
你应该使用哪一个成语? 第一个使用Runnable对象的习惯用法更为普遍,因为Runnable对象可以inheritanceThread以外的类。 第二个习惯用法在简单的应用程序中更容易使用,但受限于您的任务类必须是Thread的后代。 本课重点介绍第一种方法,它将Runnable任务与执行任务的Thread对象分开。 这种方法不仅更加灵活,而且适用于后面介绍的高级线程pipe理API。
换句话说,实现Runnable
将在您的类扩展除Thread
以外的类的场景中工作。 Java不支持多重inheritance。 另外,使用某些高级线程pipe理API时,不能扩展Thread
。 扩展Thread
最好的唯一方法是在一个小的应用程序中,将来不会更新。 实现Runnable
几乎总是更好,因为随着项目的增长,它更加灵活。 devise更改不会产生重大影响,因为您可以在java中实现多个接口,但只扩展一个类。
1)Java不支持多重inheritance,这意味着你只能扩展Java中的一个类,所以一旦你扩展了Thread类,你就失去了机会,不能扩展或inheritanceJava中的另一个类。
2) In Object oriented programming extending a class generally means adding new functionality, modifying or improving behaviors. If we are not making any modification on Thread than use Runnable interface instead.
3) Runnable interface represent a Task which can be executed by either plain Thread or Executors or any other means. so logical separation of Task as Runnable than Thread is good design decision.
4) Separating task as Runnable means we can reuse the task and also has liberty to execute it from different means. since you can not restart a Thread once it completes. again Runnable vs Thread for task, Runnable is winner.
5) Java designer recognizes this and that's why Executors accept Runnable as Task and they have worker thread which executes those task.
6) Inheriting all Thread methods are additional overhead just for representing a Task which can can be done easily with Runnable.
If I am not wrong, it's more or less similar to
界面和抽象类有什么区别?
extends establishes " Is A " relation & interface provides " Has a " capability.
Prefer implements Runnable :
- If you don't have to extend Thread class and modify Thread API default implementation
- If you are executing a fire and forget command
- If You are already extending another class
Prefer " extends Thread " :
- 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
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:
- thread handling in your application (ie. querying and modifying the execution context)
- 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
-
Ideally you should never extend the Thread class; the
Thread
class should be madefinal
. At least its methods likethread.getId()
. See this discussion for a bug related to extendingThread
s. -
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.
The simplest explanation would be by implementing Runnable
we can assign the same object to multiple threads and each Thread
shares the same object states and behavior.
For example, suppose there are two threads, thread1 puts an integer in an array and thread2 takes integers from the array when the array is filled up. Notice that in order for thread2 to work it needs to know the state of array, whether thread1 has filled it up or not.
Implementing Runnable
lets you to have this flexibility to share the object whereas extends Thread
makes you to create new objects for each threads therefore any update that is done by thread1 is lost to thread2.