创建多线程的三种方式

继承Thread类

通过继承Thread类来创建并启动多线程的步骤为:

  1. 定义Thread类的子类,并继承重写该类的run()方法,该run()方法就代表该线程要完成的任务。
  2. 创建Thread子类的实例
  3. 调用该实例对象的start()方法启动该线程

实现Runnable接口创建线程类

步骤如下:

  1. 定义Runnable接口的实现类,重写该接口的run()方法
  2. 创建Runnable接口的实例,并用该实例对象作为Thread的target来创建Thread对象,该Thread才是真正的线程对象
  3. 调用线程对象的start方法启动该线程

例子(SecondThread实现了Runnable接口):

1
2
var st = new SecondThread();
Thread thread = new Thread(st);

使用Callable和Future创建线程

Callable接口提供了call()方法来作为线程执行体,但是call方法比run方法功能更强大

  • call方法可以有返回值
  • call方法可以声明抛出异常

Java提供了Future接口来代表Callable接口call方法的返回值,并且为Future提供了一个FutureTask实现类,该实现类实现了Future接口,并且实现了Runnable接口,可以作为Thread类的target。

在Future接口定义了几个公共方法控制与它关联的Callable任务


boolean cancel(boolean mayInterruptRunning)

功能:试图取消该Future关联的Callable任务

参数:

  • mayInterruptRunning

返回值:一个布尔值


V get()

功能:返回Callable任务中的返回值,调用该任务,将导致程序阻塞,必须等到子线程结束才会得到返回值

参数:无

返回值:指定返回值


V get(long timeout, TimeUnit unit)

功能:返回Callable任务里call任务的返回值,该方法让程序最多阻塞timeout和unit指定的时间,如果经过指定时间仍然没有返回值,将抛出TimeoutException异常


boolean isCanceled()

功能:如果该Callable任务在正常完成前被取消,则返回true


boolean isDone()

功能:如果该任务已经完成,返回true


Callable接口有泛型限制,Callable接口里的泛型形参类型和call方法返回值相同,而且Callable接口为函数式接口,可以直接使用Lambda表达式创建Callable对象。

步骤为:

  1. 创建Callable接口的实现类,并实现call方法,创建实例对象
  2. 使用FutureTask来包装该实现类,该FutureTask对象封装了该Callable对象的call方法
  3. 使用FutureTask对象作为Thread对象的target创建线程对象,并启动线程
  4. 调用FutureTask对象的get方法来获得返回值

三种创建对象的方式对比

实现Runnable接口和实现Callable接口的方式基本差不多,只是Callable接口里可以有返回值,可以声明抛出异常。因此可以将两种实现接口的方法归为一种方式,和继承Thread类的主要区别有:

  1. 线程类只是实现了接口,还可以继承其他类
  2. 在这种方式下,多个线程可以共享一个target对象,所以非常适合多个线程处理一份资源的情况,从而可以将CPU,代码和数据分开,形成清晰模型
  3. 劣势是,编程稍微复杂,如果需要访问当前线程,则必须使用Thread.currentThread方法

采用继承Thread类的方法创建多线程优缺点为:

  1. 劣势是,因为线程类已经继承了Thread,不能再继承其他类
  2. 优势是,编程简单,如果要访问当前线程,直接使用this

综上,一般推荐采用Runnable接口、Callable接口来创建多线程。


创建多线程的三种方式
https://zhaoquaner.github.io/2022/05/11/Java/多线程/创建多线程的三种方式/
更新于
2022年5月22日
许可协议