1.简介
“我应该实现Runnable还是扩展Thread类”?是一个很常见的问题。
在本文中,我们将看到哪种方法在实践中更有意义以及为什么。
2.使用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() throws Exception {
Thread thread = new SimpleThread(
"SimpleThread executed using Thread");
thread.start();
thread.join();
}
我们还可以使用ExecutorService来执行线程:
@Test
public void whenSubmitToES_thenResult() throws Exception {
executorService.submit(new SimpleThread(
"SimpleThread executed using ExecutorService")).get();
}
这是在单独的线程中运行单个日志操作的相当多的代码。
另请注意,SimpleThread不能扩展任何其他类,因为Java不支持多重继承。
3.实现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() throws Exception {
Thread thread = new Thread(new SimpleRunnable(
"SimpleRunnable executed using Thread"));
thread.start();
thread.join();
}
我们甚至可以使用ExecutorService:
@Test
public void whenSubmitToES_thenResult() throws Exception {
executorService.submit(new SimpleRunnable(
"SimpleRunnable executed using ExecutorService")).get();
}
由于我们现在正在实现一个接口,如果需要,我们可以自由扩展另一个基类。
从Java 8开始,任何公开单个抽象方法的接口都被视为一个功能接口,这使它成为一个有效的lambda表达式目标。
我们可以使用lambda表达式重写上面的Runnable代码:
@Test
public void givenARunnableLambda() throws Exception {
executorService.submit(
() -> log.info("Lambda runnable executed!"));
}
4. Runnable还是Thread?
简而言之,我们通常鼓励使用Runnable over Thread:
在扩展Thread类时,我们不会覆盖它的任何方法。相反,我们覆盖的方法Runnable接口(其中主题恰好实现)。这显然违反了IS-A Thread原则
创建Runnable的实现并将其传递给Thread类利用了合成而不是继承 - 这更灵活
在扩展Thread类之后,我们无法扩展任何其他类
从Java 8开始,Runnables可以表示为lambda表达式
5.结论
在这个快速教程中,我们看到了实现Runnable通常比扩展Thread类更好的方法。
微信关注:Java知己,
每天更新Java知识哦,期待你的到来!