问题 “实现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
这两个代码块有什么显着差异吗?
3139
2018-02-12 14:28
起源
答案:
是的:实施 Runnable
是IMO的首选方式。你并不是真正专注于线程的行为。你只是给它一些东西来运行。这意味着 组成 是个 哲学 “更纯粹”的方式去。
在 实际的 条款,这意味着你可以实施 Runnable
并从另一个类扩展。
1447
2018-02-12 14:32
tl; dr:实现Runnable更好。但是,警告很重要
一般来说,我建议使用类似的东西 Runnable
而不是 Thread
因为它允许你保持你的工作只与你选择的并发松散耦合。例如,如果您使用 Runnable
并且稍后决定这实际上并不需要它自己 Thread
,你可以调用threadA.run()。
警告: 在这里,我强烈反对使用原始线程。我更喜欢使用 可调用 和 FutureTasks (来自javadoc:“可取消的异步计算”)。超时,正确取消和现代并发支持的线程池的集成对我来说比成堆的原始线程更有用。
跟进: 有一个 FutureTask
构造函数 这允许您使用Runnables(如果这是您最熟悉的)并且仍然可以获得现代并发工具的好处。引用javadoc:
如果您不需要特定结果,请考虑使用以下形式的结构:
Future<?> f = new FutureTask<Object>(runnable, null)
所以,如果我们更换他们的 runnable
和你的 threadA
,我们得到以下内容:
new FutureTask<Object>(threadA, null)
另一个让你更接近Runnables的选择是 的ThreadPoolExecutor。你可以使用 执行 传入Runnable以在将来的某个时间执行“给定任务”的方法。
如果您想尝试使用线程池,上面的代码片段将变为类似以下内容(使用 Executors.newCachedThreadPool() 工厂方法):
ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());
494
2018-02-12 14:37
故事的道德启示:
仅在您要覆盖某些行为时继承。
或者更确切地说,它应该被理解为:
继承少,界面更多。
226
2018-03-11 15:50
那么多好的答案,我想在此添加更多。这有助于理解 Extending v/s Implementing Thread
。
Extends非常紧密地绑定两个类文件,并且可能导致一些非常难以处理的代码。
两种方法都做同样的工作,但存在一些差异。
最常见的区别是
- 当您扩展Thread类时,之后您无法扩展您需要的任何其他类。 (如您所知,Java不允许继承多个类)。
- 实现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实例并将其自身作为目标传递。
在大多数情况下,如果您只打算覆盖,则应使用Runnable接口 run()
方法,没有其他Thread方法。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应对类进行子类化。
当需要扩展超类时,实现Runnable接口比使用Thread类更合适。因为我们可以在实现Runnable接口的同时扩展另一个类来创建一个线程。
我希望这个能帮上忙!
185
2018-03-05 14:26
我还没有提到的一件事就是实施 Runnable
让你的课程更灵活。
如果你扩展线程,那么你正在做的动作总是在一个线程中。但是,如果你实施 Runnable
它不一定是。您可以在一个线程中运行它,或者将它传递给某种执行器服务,或者只是作为单个线程应用程序中的任务传递它(可能在以后运行,但在同一个线程内)。如果你只是使用,选项会更开放 Runnable
而不是你自己约束自己 Thread
。
73
2018-02-12 14:51
如果你想实现或扩展任何其他类 Runnable
如果您不希望任何其他类扩展或实现,那么接口是最优选的 Thread
上课是可取的
最常见的区别是

当你 extends Thread
在此之后,您无法扩展您需要的任何其他课程。 (如您所知,Java不允许继承多个类)。
当你 implements Runnable
,您可以为您的班级节省空间,以便将来或现在扩展任何其他课程。
Java不支持多重继承,这意味着你只能在Java中扩展一个类,所以一旦你扩展了Thread类,你就失去了机会,无法在Java中扩展或继承另一个类。
在面向对象的编程中,扩展类通常意味着添加新功能,修改或改进行为。如果我们不在Thread上进行任何修改,那么请改用Runnable接口。
Runnable接口表示一个Task,它可以由普通的Thread或Executor或任何其他方法执行。所以将Task作为Runnable与Thread进行逻辑分离是一个很好的设计决策。
将任务分离为Runnable意味着我们可以重用该任务,并且可以自由地从不同的方式执行它。因为一旦完成就无法重启线程。再次Runnable vs Thread for task,Runnable是胜利者。
Java设计者认识到这一点,这就是Executors接受Runnable作为Task的原因,他们有工作线程来执行这些任务。
继承所有Thread方法只是用于表示可以使用Runnable轻松完成的Task的额外开销。
礼貌来自 javarevisited.blogspot.com
这些是Java中Thread和Runnable之间的一些显着差异,如果你知道Thread vs Runnable上的任何其他差异,请通过评论分享。我个人在这种情况下使用Runnable over Thread,并建议根据您的要求使用Runnable或Callable接口。
但是,显着的区别是。
当你 extends Thread
class,每个线程创建唯一对象并与之关联。
当你 implements Runnable
,它与多个线程共享同一个对象。
65
2018-05-11 08:59
实际上,比较并不明智 Runnable
和 Thread
彼此。
这两者在多线程中具有依赖关系和关系 Wheel and Engine
机动车的关系。
我想说,只有一种方法可以通过两个步骤实现多线程。让我说明我的观点。
可运行:
实施时 interface Runnable
这意味着你正在创造一些东西 run able
在另一个线程中。现在创建可以在线程内运行的东西(在线程内可运行)并不意味着创建一个Thread。
所以上课 MyRunnable
只不过是一个普通的班级 void run
方法。
它的对象将是一些只有一个方法的普通对象 run
它会在被调用时正常执行。 (除非我们在一个线程中传递对象)。
线:
class Thread
,我会说一个非常特殊的类,具有启动新线程的能力,实际上可以通过它实现多线程 start()
方法。
为什么不明智地比较?
因为我们需要它们用于多线程。
对于多线程,我们需要两件事:
- 可以在Thread(Runnable)中运行的东西。
- 可以启动新线程(线程)的东西。
从技术上和理论上来说,两者都是开始一个线程所必需的 跑 一个会 让它运行 (喜欢 Wheel and Engine
汽车)。
这就是你无法启动线程的原因 MyRunnable
你需要将它传递给一个实例 Thread
。
但 可以仅使用创建和运行线程 class Thread
因为上课 Thread
器物 Runnable
所以我们都知道 Thread
也是一个 Runnable
内。
最后 Thread
和 Runnable
对于多线程而不是竞争对手或替代品,它们是相互补充的。
61
2018-05-12 13:50
您应该实现Runnable,但如果您在Java 5或更高版本上运行,则不应该启动它 new Thread
但是用一个 ExecutorService的 代替。详情见: 如何在Java中实现简单的线程。
41
2018-02-12 14:41
我不是专家,但我可以想到实现Runnable而不是扩展Thread的一个原因:Java只支持单继承,所以你只能扩展一个类。
编辑:这最初说“实现一个接口需要更少的资源。”同样,但你需要创建一个新的Thread实例,所以这是错误的。
31
2018-02-12 14:32
我想说还有第三种方式:
public class Something {
public void justAnotherMethod() { ... }
}
new Thread(new Runnable() {
public void run() {
instanceOfSomething.justAnotherMethod();
}
}).start();
也许这有点受到我最近大量使用Javascript和Actionscript 3的影响,但是这样你的类不需要实现一个非常模糊的界面 Runnable
。
19
2017-10-25 21:41