Implementing a Runnable vs Extending a Thread – 实现一个可运行的线程与扩展一个线程

最后修改: 2017年 11月 7日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

“Should I implement a Runnable or extend the Thread class”? is quite a common question.

“我应该实现一个Runnable还是扩展Thread类?”这是一个相当常见的问题。

In this article, we’ll see which approach makes more sense in practice and why.

在这篇文章中,我们将看到哪种方法在实践中更有意义以及为什么。

2. Using Thread

2.使用线程

Let’s first define a SimpleThread class that extends Thread:

让我们首先定义一个SimpleThread类,它继承了Thread

public class SimpleThread extends Thread {

    private String message;

    // standard logger, constructor

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

Let’s also see how we can run a thread of this type:

让我们也来看看我们如何运行这种类型的线程。

@Test
public void givenAThread_whenRunIt_thenResult()
  throws Exception {
 
    Thread thread = new SimpleThread(
      "SimpleThread executed using Thread");
    thread.start();
    thread.join();
}

We can also use an ExecutorService to execute the thread:

我们也可以使用一个ExecutorService来执行线程。

@Test
public void givenAThread_whenSubmitToES_thenResult()
  throws Exception {
    
    executorService.submit(new SimpleThread(
      "SimpleThread executed using ExecutorService")).get();
}

That’s quite a lot of code for running a single log operation in a separate thread.

对于在一个单独的线程中运行一个单一的日志操作,这是相当多的代码。

Also, note that SimpleThread cannot extend any other class, as Java doesn’t support multiple inheritance.

另外,请注意,SimpleThread不能扩展任何其他类,因为Java不支持多重继承。

3. Implementing a Runnable

3.实现一个Runnable

Now, let’s create a simple task which implements the java.lang.Runnable interface:

现在,让我们创建一个简单的任务,实现java.lang.Runnable接口。

class SimpleRunnable implements Runnable {
	
    private String message;
	
    // standard logger, constructor
    
    @Override
    public void run() {
        log.info(message);
    }
}

The above SimpleRunnable is just a task which we want to run in a separate thread.

上面的SimpleRunnable只是一个任务,我们想在一个单独的线程中运行。

There’re various approaches we can use for running it; one of them is to use the Thread class:

我们可以使用各种方法来运行它;其中之一是使用Thread类。

@Test
public void givenRunnable_whenRunIt_thenResult()
 throws Exception {
    Thread thread = new Thread(new SimpleRunnable(
      "SimpleRunnable executed using Thread"));
    thread.start();
    thread.join();
}

We can even use an ExecutorService:

我们甚至可以使用一个ExecutorService

@Test
public void givenARunnable_whenSubmitToES_thenResult()
 throws Exception {
    
    executorService.submit(new SimpleRunnable(
      "SimpleRunnable executed using ExecutorService")).get();
}

We can read more about ExecutorService in here.

我们可以在这里阅读更多关于ExecutorService的信息。

Since we’re now implementing an interface, we’re free to extend another base class if we need to.

由于我们现在实现的是一个接口,如果需要的话,我们可以自由地扩展另一个基类。

Starting with Java 8, any interface which exposes a single abstract method is treated as a functional interface, which makes it a valid lambda expression target.

从Java 8开始,任何暴露出单一抽象方法的接口都被视为一个功能接口,这使得它成为有效的lambda表达式目标。

We can rewrite the above Runnable code using a lambda expression:

我们可以使用lambda表达式重写上述Runnable代码

@Test
public void givenARunnableLambda_whenSubmitToES_thenResult() 
  throws Exception {
    
    executorService.submit(
      () -> log.info("Lambda runnable executed!"));
}

4. Runnable or Thread?

4.RunnableThread

Simply put, we generally encourage the use of Runnable over Thread:

简单地说,我们通常鼓励使用Runnable而不是Thread

  • When extending the Thread class, we’re not overriding any of its methods. Instead, we override the method of Runnable (which Thread happens to implement). This is a clear violation of IS-A Thread principle
  • Creating an implementation of Runnable and passing it to the Thread class utilizes composition and not inheritance – which is more flexible
  • After extending the Thread class, we can’t extend any other class
  • From Java 8 onwards, Runnables can be represented as lambda expressions

5. Conclusion

5.结论

In this quick tutorial, we saw how implementing Runnable is typically a better approach than extending the Thread class.

在这个快速教程中,我们看到实现Runnable通常是比扩展Thread类更好的方法。

The code for this post can be found over on GitHub.

这篇文章的代码可以在GitHub上找到over