java并发系列-实现runnable接口类vs继承thread

1 简介

这篇文章介绍实现Runnable接口类还是继承Thread类在具体场景中,哪种更合适,为什么更合适。

2 使用线程(Thread)

首先,定义一个继承Thread的类SimpleThread:

1
2
3
4
5
6
7
8
9
10
11
public class SimpleThread extends Thread {

private String message;

// standard logger, constructor

@Override
public void run() {
log.info(message);
}
}

然后,看看怎样执行这种类型的线程:

1
2
3
4
5
6
7
8
9
@Test
public void givenAThread_whenRunIt_thenResult()
throws Exception {

Thread thread = new SimpleThread(
"SimpleThread executed using Thread");
thread.start();
thread.join();
}

也可以用ExecutorService执行这个线程:

1
2
3
4
5
6
7
@Test
public void givenAThread_whenSubmitToES_thenResult()
throws Exception {

executorService.submit(new SimpleThread(
"SimpleThread executed using ExecutorService")).get();
}

看起来写了很多代码,为了实现在一个线程中执行记录日志操作。

同时,SimpleThread类也不能再继承其他类,因为Java不支持多继承。

3 实现runnable接口类

首先,创建一个实现了java.lang.Runnable接口类的任务类SimpleRunnable

1
2
3
4
5
6
7
8
9
10
11
class SimpleRunnable implements Runnable {

private String message;

// standard logger, constructor

@Override
public void run() {
log.info(message);
}
}

怎样在线程中执行SimpleRunnable这个任务类?有很多方式,其中一种是使用Thread类:

1
2
3
4
5
6
7
8
@Test
public void givenRunnable_whenRunIt_thenResult()
throws Exception {
Thread thread = new Thread(new SimpleRunnable(
"SimpleRunnable executed using Thread"));
thread.start();
thread.join();
}

也可以使用ExecutorService

1
2
3
4
5
6
7
@Test
public void givenARunnable_whenSubmitToES_thenResult()
throws Exception {

executorService.submit(new SimpleRunnable(
"SimpleRunnable executed using ExecutorService")).get();
}

关于ExecutorService的更多知识在这里

这里的SimpleRunnable类只实现了一个接口类,所以有需要的话还能继承其他类。

从Java8开始,任何只暴露一个抽象方法的接口类也被看作是函数式接口,可以用lambda表达式来表示。所以可以用lambda表达式重写上面Runnable代码。

1
2
3
4
5
6
7
@Test
public void givenARunnableLambda_whenSubmitToES_thenResult()
throws Exception {

executorService.submit(
() -> log.info("Lambda runnable executed!"));
}

4 Runnable 或 Thread

通常比起Thread,更推荐用Runnable,原因如下:

  • 继承Thread类的时候,我们不能覆盖它的任何方法。反之,可以覆盖Runnable的方法(Thread happens to implement ???)。这明显违反了IS-A Thread的原则。(不太明白这句啥意思)
  • 创建Runnable的实现并将它传给Thread类执行,通过组合的方式而不是继承,更加灵活。
  • 继承了Thread类,不能再继承其他类
  • 从Java8开始,Runnable可以通过lambda表达式来表示

5 总结

通过这篇短文知道,实现Runnable接口类的方式比继承Thread类有更多优势。


本文为译文,作者通过翻译达到学习目的。 原文链接 | 原文源码链接