Java使用线程实现异步运行

news/2024/10/6 4:45:54/文章来源:https://www.cnblogs.com/TS86/p/18286249

在Java中,实现异步运行的一个常用方式是使用Thread类。下面,我将给出一个详细且完整的示例,该示例将创建一个简单的异步任务,该任务将模拟一个耗时的操作(比如,模拟网络请求或文件处理)。

1. 使用Thread类实现异步运行

假设我们有一个任务,该任务需要模拟一个耗时操作,比如从网络下载一个大文件。我们将使用Thread类来异步执行这个任务,以便主程序可以继续执行其他任务,而不需要等待下载完成。

public class AsyncTaskExample {  // 模拟耗时任务的Runnable实现  static class LongRunningTask implements Runnable {  @Override  public void run() {  // 模拟耗时操作,例如网络请求或文件处理  try {  // 使用Thread.sleep来模拟耗时操作  System.out.println("开始执行耗时任务...");  Thread.sleep(5000); // 假设这个任务是耗时5秒的  System.out.println("耗时任务完成!");  } catch (InterruptedException e) {  Thread.currentThread().interrupt(); // 保持中断状态  System.out.println("任务被中断!");  }  }  }  public static void main(String[] args) {  // 创建Runnable实例  Runnable task = new LongRunningTask();  // 创建Thread实例,并将Runnable作为任务传递  Thread thread = new Thread(task);  // 启动线程  System.out.println("启动异步任务...");  long startTime = System.currentTimeMillis(); // 记录开始时间  thread.start(); // 启动线程,注意start()方法调用后,线程将独立执行  // 主线程继续执行,不等待异步任务完成  for (int i = 0; i < 5; i++) {  System.out.println("主线程正在执行其他任务... " + i);  try {  Thread.sleep(1000); // 模拟主线程正在执行其他任务  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  }  long endTime = System.currentTimeMillis(); // 记录结束时间  System.out.println("主线程结束,耗时:" + (endTime - startTime) + "毫秒");  // 注意:这里的代码不会等待异步线程完成,如果你需要等待异步线程完成,可以调用thread.join();  // 但是在这个例子中,我们不会这样做,以展示异步执行的特性  }  
}

代码解释:

(1)LongRunningTask:这是一个实现了Runnable接口的类,用于封装耗时的任务。在这个例子中,我们使用Thread.sleep(5000)来模拟耗时操作。

(2)main方法

  • 创建一个LongRunningTask的实例。
  • 使用这个实例作为参数创建一个Thread对象。
  • 调用thread.start()来启动线程,这将导致LongRunningTaskrun方法在新线程中异步执行。
  • 在主线程中,我们使用一个循环来模拟主线程正在执行的其他任务,并使用Thread.sleep(1000)来模拟这些任务的耗时。
  • 注意到主线程不会等待异步线程完成,它将继续执行直到循环结束。

注意事项:

  • 异步执行意味着主线程和异步线程将并行执行,互不干扰。
  • 如果需要主线程等待异步线程完成,可以调用thread.join()。但在上面的示例中,我们没有这样做以展示异步执行的特性。
  • 在处理多线程时,要特别注意线程安全和资源同步问题。上面的示例较为简单,没有涉及到这些高级概念。但在实际应用中,这些问题可能非常重要。

除了直接使用Thread类之外,Java还提供了其他几种实现异步运行的方法。以下是一些常用的方法,并给出详细的代码示例。

2. 使用ExecutorService

ExecutorServicejava.util.concurrent包中的一个接口,它提供了一种更灵活的方式来管理线程池中的线程。使用ExecutorService可以方便地控制线程的数量、执行异步任务,并获取任务执行的结果。

import java.util.concurrent.Callable;  
import java.util.concurrent.ExecutionException;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  public class ExecutorServiceExample {  // 模拟耗时任务的Callable实现  static class LongRunningTask implements Callable<String> {  @Override  public String call() throws Exception {  // 模拟耗时操作  Thread.sleep(5000);  return "任务完成";  }  }  public static void main(String[] args) {  // 创建一个固定大小的线程池  ExecutorService executor = Executors.newFixedThreadPool(2);  // 提交任务并获取Future对象  Future<String> future = executor.submit(new LongRunningTask());  // 主线程继续执行其他任务  System.out.println("主线程正在执行其他任务...");  try {  // 如果需要,可以等待异步任务完成并获取结果  String result = future.get(); // 这将会阻塞,直到任务完成  System.out.println("异步任务结果: " + result);  } catch (InterruptedException | ExecutionException e) {  e.printStackTrace();  }  // 关闭线程池(注意:这不会立即停止正在执行的任务)  executor.shutdown();  // 如果你想立即停止所有正在执行的任务,可以使用shutdownNow(),但这通常不是推荐的做法  // executor.shutdownNow();  }  
}

3. 使用CompletableFuture

CompletableFuture是Java 8引入的一个类,它实现了FutureCompletionStage接口,提供了更丰富的异步编程能力。CompletableFuture可以显式地处理异步操作的结果,并且可以链式调用其他异步操作。

import java.util.concurrent.CompletableFuture;  public class CompletableFutureExample {  // 模拟耗时任务的Runnable  static Runnable longRunningTask = () -> {  try {  // 模拟耗时操作  Thread.sleep(5000);  System.out.println("耗时任务完成!");  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  };  public static void main(String[] args) {  // 使用runAsync方法提交一个异步任务,但不关心其结果  CompletableFuture.runAsync(longRunningTask);  // 如果你想处理异步任务的结果,可以使用supplyAsync(返回结果)或thenApply等方法  // 例如:  CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {  // 模拟耗时操作并返回结果  try {  Thread.sleep(3000);  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  return "异步任务结果";  });  // 链式调用处理结果  future.thenAccept(result -> System.out.println("处理结果: " + result));  // 主线程继续执行其他任务  System.out.println("主线程正在执行其他任务...");  // 注意:main方法会立即结束,因为CompletableFuture的操作是异步的。  // 如果需要等待异步任务完成,可以调用future.join()(但注意,CompletableFuture没有join方法,这里只是示意)  // 或者使用future.get(),但这会阻塞当前线程直到任务完成。  // 为了演示,我们可以简单地让主线程等待一段时间  try {  Thread.sleep(6000); // 等待足够长的时间以确保异步任务完成  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  }  
}  // 注意:上面的CompletableFuture示例中,我使用了Thread.sleep来模拟等待异步任务完成,  
// 这在实际应用中通常不是最佳实践。在实际应用中,你可能需要更复杂的逻辑来处理异步任务的结果。

请注意,CompletableFutureget()方法会阻塞当前线程直到异步任务完成,这与Future.get()的行为相同。

4. 如何在Java中实现异步运行

在Java中实现异步运行,通常指的是在不阻塞当前线程的情况下执行耗时操作或长时间运行的任务。Java提供了多种机制来实现异步编程,包括使用ExecutorServiceCompletableFutureFuture接口,以及Java 9及以后版本中引入的Flow.PublisherFlow.Subscriber(Reactive Streams API)等。以下是几种常见的实现异步运行的方法:

4.1 使用ExecutorService

ExecutorServicejava.util.concurrent包中的一个接口,它提供了一种管理线程池的方法,允许我们提交任务给线程池中的线程执行,而不需要显式地创建和管理线程。

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  public class AsyncExecutorService {  public static void main(String[] args) {  // 创建一个固定大小的线程池  ExecutorService executor = Executors.newFixedThreadPool(2);  // 提交任务给线程池执行  executor.submit(() -> {  // 耗时任务  System.out.println("异步任务开始执行...");  try {  Thread.sleep(5000); // 模拟耗时操作  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  System.out.println("异步任务执行完成!");  });  // 主线程继续执行其他任务  System.out.println("主线程继续执行...");  // 注意:通常应该关闭ExecutorService,但这里为了简化示例没有包含关闭代码  // executor.shutdown();  }  
}

4.2 使用CompletableFuture

CompletableFuture是Java 8引入的一个类,用于编写异步代码。它实现了FutureCompletionStage接口,提供了丰富的API来处理异步编程中的结果。

import java.util.concurrent.CompletableFuture;  public class AsyncCompletableFuture {  public static void main(String[] args) {  // 使用supplyAsync提交一个返回结果的异步任务  CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {  // 耗时任务  try {  Thread.sleep(5000); // 模拟耗时操作  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  return "异步任务结果";  });  // 异步处理结果  future.thenAccept(result -> System.out.println("处理结果: " + result));  // 主线程继续执行其他任务  System.out.println("主线程继续执行...");  // 注意:通常不需要显式等待CompletableFuture完成,因为它会自动在后台执行  // 但如果你需要等待结果,可以使用future.join()(注意:CompletableFuture没有join方法,这里只是示意)  // 或者使用future.get(),但这会阻塞当前线程  }  
}  // 注意:CompletableFuture没有join方法,但你可以使用future.get()来阻塞等待结果,  
// 或者使用future.thenRun(Runnable)等方法来在任务完成后执行某些操作,而不会阻塞当前线程。

4.3 使用Future

虽然Future接口本身不提供直接创建异步任务的方法,但它通常与ExecutorService一起使用来接收异步执行的结果。

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  public class AsyncFuture {  public static void main(String[] args) throws Exception {  // 创建一个ExecutorService  ExecutorService executor = Executors.newSingleThreadExecutor();  // 提交任务并获取Future对象  Future<String> future = executor.submit(() -> {  // 耗时任务  Thread.sleep(5000); // 模拟耗时操作  return "异步任务结果";  });  // 主线程继续执行其他任务  System.out.println("主线程继续执行...");  // 等待异步任务完成并获取结果  // 注意:这会阻塞当前线程直到任务完成  String result = future.get();  System.out.println("异步任务结果: " + result);  // 关闭ExecutorService  executor.shutdown();  }  
}

4.4 总结

以上是在Java中实现异步运行的几种常见方法。选择哪种方法取决于我们的具体需求,比如是否需要处理异步结果、是否需要控制线程池的大小、是否偏好使用Java 8的lambda表达式等。在实际应用中,通常建议使用ExecutorServiceCompletableFuture,因为它们提供了更灵活和强大的异步编程能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/738860.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

米尔瑞米派集聚5种操作系统,兼顾学习开发和项目产品需要的派

米尔电子发布的瑞萨第一款MPU生态板卡-瑞米派(Remi Pi),采用瑞萨RZ/G2L双核A55芯片,接口丰富,全面兼容树莓派的扩展模块。瑞米派支持五种系统,兼顾学习开发和项目产品需要。软件提供五种软件系统分别为:基于Yocto构建的两种系统,一种是支持通用功能的精简型系统,另一种…

echarts中Label标签与数据项颜色设置为同一种颜色

echarts5中默认标签颜色不会跟数据项颜色保持一致,而是全都是黑色。想要实现label颜色和它的数据项颜色一致,需要手动继承颜色,设置label{ color: inherit}即可解决label标签颜色与数据项颜色一致。 https://echarts.apache.org/examples/zh/editor.html?c=pie-simple 注意…

GaussDB AI新特性:gs_index_advise推荐索引

GaussDB的AI新特性,可以把SQL文本嵌套在函数中,数据库会返回一个创建合适索引的列gs_index_advise(text) 描述:针对单条查询语句推荐索引。 参数: SQL语句字符串 返回值类型: record 一、通常的SQL优化会通过参数调优的方式进行调整,例如如下参数set enable_fast_query_s…

Packing Python to exe(打包Python成EXE文件)

Python文件要执行需要Python环境,如果package成EXE文件则可以随意放在任意主机上去执行。package步骤如下: 1. 安装pythoninstaller (pip install pyinstaller) 2.安装auto-py-to-exe(有UI界面,很方便使用)(pip install auto-py-to-exe) 3.然后直接运行命令auto-py-to-e…

Sqlalchemy 连接SQL Server 登录失败

实验系统环境 Windows平台 Sqlalchemy 2.0.23 Python 3.10 SQL Server 2012 aioodbc 0.5.0 问题详情 sqlalchemy.exc.InterfaceError: (pyodbc.InterfaceError) (28000, [28000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]登录失败。该登录名来自不受信任的域,不…

电脑使用什么远程控制软件?推荐使用安全软件ToDesk

当你面临紧急工作需求,但却和办公电脑相隔千里时,远程控制电脑就派上了用场! 初次使用远程控制软件的人,可能会担心使用时会不会存在信息被盗取,使用过后会不会发生被陌生人悄悄远控的情况 小社长向大家安利一个超好用的远程控制软件ToDesk!电脑远程控制高清不卡顿,传输…

便宜SSL证书申请Lets Encrypt泛域名SSL证书

随着互联网的飞速发展,网络安全问题愈发凸显其重要性。而HTTPS协议作为保障网站数据传输安全的重要手段,已经得到了广泛的应用。 申请Lets Encrypt便宜泛域名SSL证书步骤1. 登录来此加密网站,输入域名,可以勾选泛域名和包含根域。2. 选择加密方式,一般选择默认就可以了,也…

ToDesk云电脑实测!轻松应对游戏电竞、AIGC创作、设计建模等场景

万物智联时代,现代社会对数字计算的需求呈指数级增长。当算力成为推动技术创新和应用发展的重要引擎,云电脑产业正在悄然占据国内算力应用的市场,成为新时代的数字经济发展方向。1云电脑,顾名思义,是一台随时运行在云上的“电脑”,操作系统、存储、运算都能在云端上进行,…

ToDesk智能无损画质是什么功能?如何使用1

能跨设备跨系统远程控制设备的ToDesk相信大家都有用过,它不仅有流畅的远控体验,而且开发了许多实用的插件功能。 比如能直接从硬盘高速传资料的文件传输功能,官方实测能达到12m/s,还有能远程开关机,太方便远程办公完需要关电脑的打工人了。最近小社长还发现ToDesk远程控制…

Mingw GCC 编译OpenCV报错: Project files may be invalid

这是一个通用报错弹窗:具体要看下边输出窗口:CMake Error: CMake was unable to find a build program corresponding to "MinGW Makefiles". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool. CMake Error: CMAKE_CXX_COMPIL…

linux部署Hugegraph

HugeGraph是一款易用、高效、通用的开源图数据库系统(Graph Database)。 一、基本概述功能特性:HugeGraph实现了Apache TinkerPop3框架,并完全兼容Gremlin查询语言,具备完善的工具链组件,助力用户轻松构建基于图数据库之上的应用和产品。它支持百亿以上的顶点和边快速导入…

ComfyUI进阶篇:ComfyUI核心节点(一)

ComfyUI进阶篇:ComfyUI核心节点(一)前言:学习ComfyUI是一场持久战。当你掌握了ComfyUI的安装和运行之后,会发现大量五花八门的节点。面对各种各样的工作流和复杂的节点种类,可能会让人感到不知所措。在这篇文章中,我们将用通俗易懂的语言对ComfyUI的核心节点进行系统梳理,…