揭秘java线程池-高效利器背后的精髓(下)-进阶多线程-Callable、Future和手写线程池实战


在Java并发编程中,仅会使用线程池是远远不够的。为了充分发挥多线程的威力,我们还需要深入理解Callable、Future和FutureTask的内在机制,并且能熟练地手写一个功能完备的线程池。让我们一同攻克这座高峰,领略并发编程的无穷魅力!


一、Callable和Future: 异步编程的钥匙

在传统的多线程编程中,我们仅能通过Runnable提交没有返回值的简单任务。而Callable则赋予了我们创建"有返回值的任务"的能力,为异步编程的大门打开了一扇窗。

Future则是Callable的完美绑定,通过它我们不仅能拿到任务的执行结果,还能判断任务的执行状态,甚至是取消任务。随着异步编程日益普及,掌握这对搭档就变得尤为重要。


Callable 接口和 Future 接口经常一起使用来执行异步任务。

Callable 接口与 Runnable 接口类似,但它可以返回结果并且可以抛出异常。

Future 接口代表异步计算的结果,并且可以用来检查计算是否完成,取消计算,以及获取计算的结果。


以下是一个使用 CallableFuture 完成异步排序任务的示例代码,其中包含异步取消、异常处理和超时控制:

import java.util.Arrays;
import java.util.concurrent.*;

public class AsyncSortExample {
    public static void main(String[] args) {
        // 创建一个线程池
        ExecutorService executor = Executors.newSingleThreadExecutor();

        try {
            // 创建一个 Callable 任务,执行排序操作
            Callable<Integer[]> callable = () -> {
                try {
                    // 模拟耗时的排序任务
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                // 假设我们对数组进行排序
                Integer[] data = {5, 3, 8, 1, 2};
                Arrays.sort(data);
                return data;
            };

            // 提交任务并获取 Future 对象
            Future<Integer[]> future = executor.submit(callable);

            // 模拟其他任务或操作...
            // ...

            // 超时控制,等待结果,设置超时时间为 3 秒
            try {
                Integer[] sortedData = future.get(3, TimeUnit.SECONDS);
                System.out.println("Sorted data: " + Arrays.toString(sortedData));
            } catch (TimeoutException e) {
                System.out.println("Task timed out, attempting to cancel...");
                // 超时后尝试取消任务
                future.cancel(true);
            } catch (CancellationException e) {
                System.out.println("Task was cancelled.");
            } catch (ExecutionException e) {
                // 处理 Callable 任务中的异常
                System.out.println("Task threw an exception: " + e.getCause().getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            executor.shutdown();
        }
    }
}

代码解释:

  1. 线程池创建:使用 Executors.newSingleThreadExecutor() 创建了一个单线程的线程池。
  2. Callable 任务定义:定义了一个 Callable 任务,该任务模拟了一个耗时的排序操作。
  3. 任务提交:通过 executor.submit(callable) 提交任务,并获得一个 Future 对象。
  4. 超时控制:使用 future.get(3, TimeUnit.SECONDS) 尝试获取结果,设置了 3 秒的超时时间。
  5. 异常处理
    • TimeoutException:如果任务执行超过 3 秒,将捕获此异常,并尝试取消任务。
    • CancellationException:如果任务已经被取消,将捕获此异常。
    • ExecutionException:如果 Callable 任务中抛出了异常,将捕获 ExecutionException 并通过 e.getCause() 获取原始异常。
  6. 取消任务:如果需要取消任务,可以使用 future.cancel(true),其中 true 参数表示中断正在执行的任务。
  7. 关闭线程池:在 finally 块中关闭线程池,释放资源。

二、FutureTask源码剖析

FutureTask的出现,为Callable和Future之间架起了一座桥梁。作为两者的融合体,它不仅可以扮演Callable执行的载体角色,自身也是一个Future实例。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w风雨无阻w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值