2026/4/18 15:46:47
网站建设
项目流程
用中文模版可以做英文网站吗,品牌设计网站建设,网站充值接口,网站空间一年多少钱在上一篇博客中#xff0c;我们提到了创建线程的 3 种方式#xff0c;一种是直接继承 Thread#xff0c;一种是实现 Runnable 接口#xff0c;另外一种是实现 Callable 接口。前 2 种方式都有一个缺陷#xff1a;在执行完任务之后无法获取执行结果。如果需要获取执行结果我们提到了创建线程的 3 种方式一种是直接继承 Thread一种是实现 Runnable 接口另外一种是实现 Callable 接口。前 2 种方式都有一个缺陷在执行完任务之后无法获取执行结果。如果需要获取执行结果就必须通过共享变量或者线程通信的方式来达到目的这样使用起来就比较麻烦。Java 1.5 提供了 Callable、Future、FutureTask它们可以在任务执行完后得到执行结果今天我们就来详细的了解一下。无返回值的 Runnable由于Runnable的run()方法的返回值为 voidpublic interface Runnable { public abstract void run(); }所以在执行完任务之后无法返回任何结果。有返回值的 CallableCallable 位于java.util.concurrent包下也是一个接口它定义了一个call()方法public interface CallableV { V call() throws Exception; }可以看到call()方法返回的类型是一个 V 类型的泛型。那怎么使用 Callable 呢一般会配合 ExecutorService来使用。ExecutorService 是一个接口位于java.util.concurrent包下它是 Java 线程池框架的核心接口用来异步执行任务。它提供了一些关键方法用来进行线程管理。下面的例子就用到了 ExecutorService 的 submit 方法。// 创建一个包含5个线程的线程池 ExecutorService executorService Executors.newFixedThreadPool(5); // 创建一个Callable任务 CallableString task new CallableString() { public String call() { return Hello from Thread.currentThread().getName(); } }; // 提交任务到ExecutorService执行并获取Future对象 Future[] futures new Future[10]; for (int i 0; i 10; i) { futures[i] executorService.submit(task); } // 通过Future对象获取任务的结果 for (int i 0; i 10; i) { System.out.println(futures[i].get()); } // 关闭ExecutorService不再接受新的任务等待所有已提交的任务完成 executorService.shutdown();我们通过 Executors 工具类来创建一个 ExecutorService然后向里面提交 Callable 任务然后通过 Future 来获取执行结果。为了做对比我们再来看一下使用 Runnable 的方式// 创建一个包含5个线程的线程池 ExecutorService executorService Executors.newFixedThreadPool(5); // 创建一个Runnable任务 Runnable task new Runnable() { public void run() { System.out.println(Hello from Thread.currentThread().getName()); } }; // 提交任务到ExecutorService执行 for (int i 0; i 10; i) { executorService.submit(task); } // 关闭ExecutorService不再接受新的任务等待所有已提交的任务完成 executorService.shutdown();可以看到使用 Runnable 的方式要比 Callable 的方式简单一些但是 Callable 的方式可以获取执行结果这是 Runnable 做不到的。异步计算结果 Future 接口在前面的例子中我们通过 Future 来获取 Callable 任务的执行结果那么 Future 是什么呢Future 位于java.util.concurrent包下它是一个接口public interface FutureV { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }一共声明了 5 个方法cancel()方法用来取消任务如果取消任务成功则返回 true如果取消任务失败则返回 false。参数 mayInterruptIfRunning 表示是否允许取消正在执行却没有执行完毕的任务如果设置 true则表示可以取消正在执行过程中的任务。如果任务已经完成则无论 mayInterruptIfRunning 为 true 还是 false此方法肯定返回 false即如果取消已经完成的任务会返回 false如果任务正在执行若 mayInterruptIfRunning 设置为 true则返回 true若 mayInterruptIfRunning 设置为 false则返回 false如果任务还没有执行则无论 mayInterruptIfRunning 为 true 还是 false肯定返回 true。isCancelled()方法表示任务是否被取消成功如果在任务正常完成前被取消成功则返回 true。isDone()方法表示任务是否已经完成若任务完成则返回 trueget()方法用来获取执行结果这个方法会产生阻塞会一直等到任务执行完毕才返回get(long timeout, TimeUnit unit)用来获取执行结果如果在指定时间内还没获取到结果就直接返回 null。也就是说 Future 提供了三种功能1判断任务是否完成2能够中断任务3能够获取任务执行结果。由于 Future 只是一个接口如果直接 new 的话编译器是会有一个警告的它会提醒我们最好使用 FutureTask。实际上FutureTask 是 Future 接口的一个唯一实现类我们在前面的例子中executorService.submit()返回的就是 FutureTask。异步计算结果 FutureTask 实现类我们来看一下 FutureTask 的实现public class FutureTaskV implements RunnableFutureVFutureTask 类实现了 RunnableFuture 接口我们看一下 RunnableFuture 接口的实现public interface RunnableFutureV extends Runnable, FutureV { void run(); }可以看出 RunnableFuture 继承了 Runnable 接口和 Future 接口而 FutureTask 实现了 RunnableFuture 接口。所以它既可以作为 Runnable 被线程执行又可以作为 Future 得到 Callable 的返回值。FutureTask 提供了 2 个构造器public FutureTask(CallableV callable) { } public FutureTask(Runnable runnable, V result) { }当需要异步执行一个计算并在稍后的某个时间点获取其结果时就可以使用 FutureTask。举个// 创建一个固定大小的线程池 ExecutorService executorService Executors.newFixedThreadPool(3); // 创建一系列 Callable CallableInteger[] tasks new Callable[5]; for (int i 0; i tasks.length; i) { final int index i; tasks[i] new CallableInteger() { Override public Integer call() throws Exception { TimeUnit.SECONDS.sleep(index 1); return (index 1) * 100; } }; } // 将 Callable 包装为 FutureTask并提交到线程池 FutureTaskInteger[] futureTasks new FutureTask[tasks.length]; for (int i 0; i tasks.length; i) { futureTasks[i] new FutureTask(tasks[i]); executorService.submit(futureTasks[i]); } // 获取任务结果 for (int i 0; i futureTasks.length; i) { System.out.println(Result of task (i 1) : futureTasks[i].get()); } // 关闭线程池 executorService.shutdown();以下是程序的执行结果