继承 Thread
类:简单易用,但灵活性差。
实现 Runnable
接口:灵活性高,适合资源共享。
使用 Callable
接口配合 FutureTask
:支持返回结果和异常处理,适合需要任务结果的场景。
使用线程池:高效管理线程资源,适合处理大量短生命周期任务。
使用 CompletableFuture
:底层依然依赖于线程池。支持链式调用和组合多个异步任务,适合复杂的异步编程场景。
无论有多少种形式,创建多线程的真正的方法,其实只有两种:
继承 Thread 类
实现 Runnable 接口
其它形式都是这两种方式的变体。
常见的多线程的实现方法及其特点
继承Thread类
流程:
- 定义一个类继承自
Thread
类,并重写run()
方法。 - 创建该类的对象,并调用其
start()
方法启动新线程。
特点:
- 简单易用:直接继承
Thread
类并重写run()
方法即可。 - 局限性:由于 Java 不支持多继承,继承
Thread
类后无法再继承其他类。 - 适用场景:适合简单的线程任务。
实现 Runnable
接口
流程:
- 定义一个类并实现
Runnable
接口的run()
方法。 - 创建该类的对象,并将其作为目标传递给一个
Thread
类的实例。 - 调用
Thread
实例的start()
方法启动新线程。
特点:
- 灵活性:实现
Runnable
接口后,类还可以继承其他类。 - 资源共享:多个线程可以共享同一个
Runnable
实例。 - 适用场景:适合需要资源共享或需要继承其他类的场景。
使用 Callable 接口配合 FutureTask
流程:
- 定义一个类并实现
Callable
接口的call()
方法。 - 创建一个
FutureTask
对象,将Callable
实例作为参数传入。 - 将
FutureTask
对象作为目标传递给一个Thread
类的实例,并启动线程。 - 通过
FutureTask
对象的get()
方法获取异步计算的结果。
特点:
- 支持返回结果和异常处理,适合需要任务结果的场景。
- 使用
Callable
接口限定的功能 +Future
接口限定的功能 = 汇总各个线程执行结果 最终执行汇总操作的这一步会被阻塞,直到前面各个线程完成了计算。 - 类兼具
Runnable
和Future
接口的功能,并方便地将两种功能组合在一起。
关于 FutureTask 类的使用有如下建议:
- 在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给 Future 对象在后台完成
- 当主线程将来需要时,就可以通过 Future 对象获得后台作业的计算结果或者执行状态
- 一般 FutureTask 多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
- 仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get() 方法
- 一旦计算完成,就不能再重新开始或取消计算
- get() 方法而获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常
- get() 只执行一次,因此get() 方法放到最后
使用线程池
流程:
- 创建一个线程池(如通过
Executors
工具类)。 - 创建一个实现
Runnable
或Callable
接口的任务类。 - 将任务提交给线程池执行(如使用
execute()
或submit()
方法)。 - 线程池会自动管理线程的创建、执行和销毁。
- 如果是
Callable
任务,可以通过Future
对象获取任务结果。 - 任务执行完成后,关闭线程池。
特点:
- 资源管理:线程池可以管理线程的生命周期,减少创建和销毁线程的开销。
- 任务队列:线程池可以处理大量任务,超出线程数的任务会被放入队列等待。
- 适用场景:适合需要处理大量短生命周期任务的场景。
使用 CompletableFuture
(Java 8+)
CompletableFuture
本身不是线程池,但它依赖于线程池来执行异步任务。
流程:
- 使用
CompletableFuture
的静态方法(如runAsync
或supplyAsync
)创建异步任务。 - 如果是
supplyAsync
,定义任务并返回结果;如果是runAsync
,定义任务但不返回结果。 - 任务默认提交到
ForkJoinPool.commonPool()
执行,也可以指定自定义线程池。 - 通过
CompletableFuture
的方法(如thenApply
、thenAccept
)定义任务完成后的回调操作。 - 如果需要,调用
join()
或get()
方法等待任务完成并获取结果。
特点:
- 异步编程:
CompletableFuture
提供了更强大的异步编程能力,支持链式调用和组合多个异步任务。 - 适用场景:适合复杂的异步任务处理场景。