掌握Java并发工具:Callable和Future实战技巧

server/2024/9/24 22:36:18/

Callable接口介绍

Callable vs Runnable

在Java中,Callable接口是一个返回结果并可能抛出异常的任务。它类似于Runnable接口,但有两个显著的不同:

  1. Callable的call()方法可以返回值。
  2. call()方法可以抛出受检查的异常。
java">import java.util.concurrent.Callable;public class WordCallable implements Callable<String> {@Overridepublic String call() throws Exception {// 休眠一秒模拟长时间运行的任务Thread.sleep(1000);return "Hello, Callable!";}
}

Callable的优势

相比于Runnable,Callable最大的优势在于它的灵活性:

  1. 它可以直接通过Future得到任务执行的结果。
  2. 能够处理更复杂的业务逻辑,因为它可以抛出异常。
  3. 它广泛应用在需要任务执行结果时。
java">import java.util.concurrent.FutureTask;public class CallableExample {public static void main(String args) throws Exception {WordCallable wordCallable = new WordCallable();FutureTask<String> futureTask = new FutureTask<>(wordCallable);new Thread(futureTask).start();// 获取异步执行的结果String result = futureTask.get();System.out.println(result);}
}

实现Callable接口的重要类分析

Executors类

Executors类是java.util.concurrent包中的一个工厂和工具类,用于创建线程池和Future对象。它提供了多种静态方法来创建不同类型的线程池,例如newFixedThreadPool、newCachedThreadPool等。

java">import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class CallableWithExecutors {public static void main(String args) throws Exception {ExecutorService executor = Executors.newSingleThreadExecutor();Callable<String> callable = new WordCallable();Future<String> future = executor.submit(callable);// 做一些其他的事情...String result = future.get();System.out.println(result);executor.shutdown();}
}

FutureTask类

FutureTask是Future的一个具体实现,它同样实现了Runnable,因此它既可以由Thread对象执行,也可以提交给ExecutorService。

java">import java.util.concurrent.FutureTask;public class FutureTaskExample {public static void main(String args) {Callable<String> callable = new WordCallable();FutureTask<String> task = new FutureTask<>(callable);new Thread(task).start();// 当需要结果时获取,可能会阻塞String result = task.get();System.out.println(result);}
}

两种异步模型与深度解析

Future接口

Future接口功能

Future接口在Java并发中是用来描述一个异步计算的结果。通过Future对象,我们可以了解任务执行情况,取消任务,以及获取执行结果。

java">import java.util.concurrent.*;public class SimpleFutureDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executorService = Executors.newFixedThreadPool(1);Future<Integer> futureResult = executorService.submit(() -> {TimeUnit.SECONDS.sleep(2);return 42;});// 任务进行中的时候可以做一些其他事情// ...// 当我们需要这个结果的时候,我们可以调用 get// 如果任务已完成,get会立即返回结果,否则会阻塞直到任务进入完成状态,然后返回结果或者抛出异常Integer result = futureResult.get();System.out.println("Future result is: " + result);executorService.shutdown();}
}

Future接口的方法解读

Future接口提供以下几个关键方法:

  • cancel:试图取消运行中的任务
  • isCancelled:返回布尔值,如果任务在正常完成前被取消,则为true
  • isDone:如果任务已完成,则返回true
  • get:等待计算完成,然后检索其结果
  • get (with timeout):如果计算已完成,则检索其结果,否则等待指定的时间
java">// 省略之前Future接口功能的代码示例...
Integer result = null;
try {// 在指定的时间内等待结果,如果任务在指定时间内完成,将返回结果,否则抛出TimeoutExceptionresult = futureResult.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {System.err.println("任务超时未获取到结果");
} catch (ExecutionException e) {System.err.println("任务执行异常");
} catch (InterruptedException e) {System.err.println("任务被中断");
}
System.out.println("Future result is: " + result);
// 关闭线程池
executorService.shutdown();

两种异步模型

file

Executor框架模型

Executor框架是Java提供的一种用来管理线程资源的框架,通过使用它可以简化多线程编程的复杂性。Executor框架主要由Executor, Executors, ExecutorService, CompletionService, ThreadPoolExecutor等组成。

java">// 示例中我们之前已经使用到了ExecutorService和Executors
// 假设我们有更多的Callable任务需要执行,我们可以使用线程池来管理这些任务

Fork/Join框架模型

Fork/Join框架主要用于并行执行任务和处理大量数据。这个模型的思想是将一个大任务分割成若干小任务,这些小任务分别执行,最后将小任务的结果合并得到大任务结果的模式。

java">import java.util.concurrent.RecursiveTask;public class FibonacciComputation extends RecursiveTask<Integer> {final int n;FibonacciComputation(int n) {this.n = n;}@Overrideprotected Integer compute() {if (n <= 1)return n;FibonacciComputation f1 = new FibonacciComputation(n - 1);f1.fork(); // 开始异步执行FibonacciComputation f2 = new FibonacciComputation(n - 2);return f2.compute() + f1.join(); // 等待异步执行结果和当前结果相加}
}

深度解析Future接口

如何取消任务

Future接口的cancel方法可以用来取消任务。如果取消成功,以后尝试通过get方法获取结果时会抛出CancellationException。

java">// 省略之前Future接口功能的代码示例...// 取消任务
boolean cancelled = futureResult.cancel(true);
// 验证任务是否已经被取消
System.out.println("Task was cancelled: " + cancelled);

如何检查任务状态

可以通过调用isDone和isCancelled方法来检查任务的状态。

java">// 省略之前Future接口功能的代码示例...// 检查任务是否已经取消
System.out.println("Task was cancelled: " + futureResult.isCancelled());
// 检查任务是否已完成
System.out.println("Task is done: " + futureResult.isDone());

处理超时

使用带有超时的get方法来处理长时间未完成的任务可能导致的等待问题。

java">// 省略之前Future接口功能的代码示例...
// 使用get(long timeout, TimeUnit unit)方法,可以防止无限期等待任务的完成。

Future接口的局限性和解决方案

尽管Future提供了对于异步任务的基本控制,它有一定的局限性,比如无法直接得知任务完成的进度,不支持完成通知,也不支持链式Future操作。Java 8引入了CompletableFuture,它提供了更多的灵活性和控制力,包括任务结果合成、异常处理、事件完成通知等。

java">import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;public class CompletableFutureDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello CompletableFuture!");// 当异步任务完成或者发生异常时,可以手动完成或者处理异常future.complete("手动完成的结果");future.exceptionally(ex -> "出现异常: " + ex.getMessage());System.out.println("CompletableFuture result: " + future.get());}
}

http://www.ppmy.cn/server/23185.html

相关文章

Docker基本操作 Linux里边操作

docker镜像操作命令: docker images:查看所有镜像; docker rmi:删除镜像 后边可以跟镜像的名字或者id指定要删除的镜像&#xff1b; docker pull:拉取镜像&#xff1b; docker push:推送镜像到服务&#xff1b; docker save :打包镜像 后边有用法; docker load:加载镜像&…

微前端技术之Web Components

Web Component 是一套技术&#xff0c;允许你创建可重用定制的元素&#xff08;它们的功能封装在你的代码之外&#xff09;并且在你的web应用中使用它们。通俗来讲就是将部分可重用的代码抽离&#xff0c;封装成一个独立的组件&#xff0c;方便在其他地方引用。 Web components…

Shader实战(3):贴图像素化风格实现

话不多说&#xff0c;将以下shader赋给材质贴上贴图即可。 Shader "HQY/Shader2" //自己改名 {Properties{_Diffuse ("Diffuse", Color) (1,1,1,1)_MainTex ("MainTex", 2D) "white" {}_Specular("Specular", Color) (…

git版本控制基础工作流

版本控制基础工作流 注意&#xff1a;在进行分支切换和合并操作前&#xff0c;建议先确保当前分支上的修改已经提交或保存&#xff0c;避免意外丢失代码。 在解决冲突时&#xff0c;可以根据实际情况选择其他辅助工具&#xff0c;如图形化界面工具或第三方合并工具。这些工具可…

jenkins搭建

安装jdk yum install -y java-1.8.0-openjdk.x86_64 默认安装到usr/lib/jvm目录下 查看JDK信息,输入命令:java -version 检测JDK安装包,输入命令:rpm -qa | grep java 进入安装目录。 输入命令:cd /usr/lib/jvm 删除Java相关文件,输入命令:rm -rf /usr/lib/jvm 配置…

spring boot 将配置文件信息 赋值到类注解

如何将application.properties中的值赋值给一个类注解呢 先看两个类 application.properties server.port8080 flow.namemyFlow flow.age20Component Documented Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) public interface UserInfo {String name() d…

谷歌TPU(Tensor Processing Unit)

谷歌TPU&#xff08;Tensor Processing Unit&#xff09; https://cloud.google.com/tpu/docs/intro-to-tpu?hlzh-cn CPU的工作模式和GPU工作模式的区别 CPU 最大的优点是它们的灵活性。您可以在 CPU 上为许多不同类型的应用加载任何类型的软件。对于每次计算&#xff0c;CPU…

WPS-EXCEL:快速删除多个线条对象

问题图 我需要将线条快速删除 方法一:使用定位对象功能 使用定位功能&#xff1a;按Ctrl G打开定位对话框。在对话框中&#xff0c;点击“定位条件”。 定位对象&#xff1a;在定位条件对话框中&#xff0c;勾选“对象”选项&#xff0c;然后点击“确定”。这样&#xff0c;…