“我应该实现Runnable还是扩展Thread类?”这是一个很常见的问题。
在本文中,我们将看到哪种方法在实践中更有意义以及为什么。
使用Thread
我们首先定义一个扩展线程Thread的SimpleThread类:
public class SimpleThread extends Thread {
private String message;
// standard logger, constructor
@Override
public void run() {
log.info(message);
}
}
让我们看看如何运行这种类型的线程:
@Test
public void givenAThread_whenRunIt_thenResult()
throws Exception {
Thread thread = new SimpleThread(
"SimpleThread executed using Thread");
thread.start();
thread.join();
}
我们还可以使用ExecutorService
来执行线程:
@Test
public void givenAThread_whenSubmitToES_thenResult()
throws Exception {
executorService.submit(new SimpleThread(
"SimpleThread executed using ExecutorService")).get();
}
在单独的线程中运行单个日志操作需要大量代码。
此外,请注意SimpleThread
不能扩展任何其他类,因为Java不支持多重继承。
实现Runnable
现在,让我们创建一个实现java.lang.Runnable
接口:
class SimpleRunnable implements Runnable {
private String message;
// standard logger, constructor
@Override
public void run() {
log.info(message);
}
}
上面的SimpleRunnable
只是一个我们希望在单独线程中运行的任务。
我们可以使用各种方法来运行它;其中之一是使用Thread类:
@Test
public void givenRunnable_whenRunIt_thenResult()
throws Exception {
Thread thread = new Thread(new SimpleRunnable(
"SimpleRunnable executed using Thread"));
thread.start();
thread.join();
}
我们甚至可以使用ExecutorService
:
@Test
public void givenARunnable_whenSubmitToES_thenResult()
throws Exception {
executorService.submit(new SimpleRunnable(
"SimpleRunnable executed using ExecutorService")).get();
}
由于我们现在正在实现一个接口,如果需要,我们可以自由扩展另一个基类。
从Java 8开始,任何公开单个抽象方法的接口都被视为函数接口,这使其成为有效的lambda表达式目标。
我们可以使用lambda表达式重写上述可运行代码:
@Test
public void givenARunnableLambda_whenSubmitToES_thenResult()
throws Exception {
executorService.submit(
() -> log.info("Lambda runnable executed!"));
}
Runnable还是Thread?
简单地说,我们通常鼓励使用Runnable
:
- 在扩展
Thread
类时,我们没有重写它的任何方法。相反,我们重写了Runnable
方法(线程恰好实现了该方法)。这明显违反了 IS-A 线程原则 - 创建
Runnable
的实现并将其传递给Thread
类利用组合而不是继承,这更灵活 - 在扩展
Thread
类之后,我们不能扩展任何其他类 - 从Java 8开始,
Runnables
可以表示为lambda表达式
结论
实现Runnable通常比扩展Thread类更好。
免责声明:本文系转载,版权归原作者所有;旨在传递信息,不代表一休教程网的观点和立场。