Java使用线程实现异步运行

在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.mzph.cn/diannao/41321.shtml

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

相关文章

【MySQL】mysql访问

mysql访问 1.引入MySQL 客户端库2.C/C 进行增删改3.查询的处理细节4.图形化界面访问数据库4.1下载MYSQL Workbench4.2MYSQL Workbench远程连接数据库 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&a…

第9章:Electron的安全性

在开发Electron应用时&#xff0c;安全性是一个非常重要的考虑因素。由于Electron应用可以访问Node.js的全部API&#xff0c;以及使用Web技术开发界面&#xff0c;因此需要特别注意安全问题。本章将介绍如何提高Electron应用的安全性&#xff0c;包括禁用不必要的功能、设置内容…

Javascript中Object、Array、String

Object 在JavaScript中&#xff0c;Object 类型是一种复杂的数据类型&#xff0c;用于存储键值对集合。它提供了多种方法来操作这些键值对&#xff0c;以及执行其他常见的操作。这里&#xff0c;我列出了一些 Object 类型的常见方法或特性&#xff0c;它们在日常编程中非常有用…

开思通智网-科技快报20240704:全球首个,人工智能之城,AI填报志愿

【本周新进展】 天大开发全球首个可开源片上脑机接口智能交互系统 https://tech.opensnn.com/chip/article/2826792 AI系统绘出“多彩”大脑布线图 https://news.sciencenet.cn/htmlnews/2024/7/525678.shtm 北京亦庄将建全域人工智能之城 https://tech.opensnn.com/chip/arti…

基于深度学习的文本框检测

基于深度学习的文本框检测&#xff08;Text Box Detection&#xff09;是一项重要的计算机视觉任务&#xff0c;旨在从图像中自动检测和定位文本区域。它在光学字符识别&#xff08;OCR&#xff09;、自动文档处理、交通标志识别等领域具有广泛的应用。以下是关于这一领域的系统…

快递物流运输中的锁控系统优缺点探讨

一、物流运输中锁控系统的重要性 1.1 保障货物安全 在物流运输过程中&#xff0c;货物安全是物流公司最为关注的问题之一。传统机械锁虽然在一定程度上提供了安全保障&#xff0c;但其缺点逐渐暴露&#xff0c;成为物流运输中的一个痛点。 易被破解&#xff1a;传统机械锁通…

drawio打开不显示,不在当前屏幕的解决方案

如果把drawio拖在外接显示器&#xff0c;关机前没有拖回主屏幕&#xff0c;那么下次打开它时如果用的不是原来那个显示器&#xff0c;它就无法正常显示。在任务栏上能看到有它&#xff0c;但是就是显示不出来。 经过卸载和其他的方式没有解决&#xff0c;就想到了&#xff0c;应…

基于MCU平台的HMI开发的性能优化与实战(下)

继上篇《基于MCU平台的HMI开发的性能优化与实战&#xff08;上&#xff09;》深入探讨了提升MCU平台HMI开发效率和应用性能的策略后&#xff0c;本文将专注于NXP i.MX RT1170 MCU平台的仪表盘开发实践。我们将重点介绍Qt for MCUs的优化技巧&#xff0c;展示如何通过实际案例应…

Qt:7.QWidget属性介绍(cursor属性-光标形状、font属性-控件文本样式、tooltip属性-控件提示信息)

目录 一、cursor属性-光标形状&#xff1a; 1.1cursor属性介绍&#xff1a; 1.2获取当前光标形状——cursor()&#xff1a; 1.3 设置光标的形状——setCursor()&#xff1a; 1.4 设置自定义图片为光标&#xff1a; 二、font属性-控件文本样式&#xff1a; 2.1font属性介绍…

antd-Table-可视化数据滚动

代码 // 使用方式 const Index () > {useScroll();return <Table />; }import { useEffect, useRef, useState } from react;export const useScroll (() > {let timer;function start() {const [isScroll, setIsScroll] useState(true);const scrollTopRef u…

代码随想录算法训练营Day59|110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长

字符串接龙 110. 字符串接龙 (kamacoder.com) 主要参考代码随想录 代码随想录 (programmercarl.com) 目标&#xff1a;得到从beginStr转变为endStr所需的最少步数 过程&#xff1a;每次变换一个字母&#xff0c;每次变换的结果要在strList中。 对于一个图来说&#xff0c;…

excel批量修改一列单价的金额并保留1位小数

1.打开表格&#xff0c;要把单价金额变成现在的两倍&#xff0c;数据如下&#xff1a; 2.把单价这一列粘贴到一个新的sheet页面&#xff0c;在B2单元格输入公式&#xff1a;A2*2 然后按enter回车键,这时候吧鼠标放到B2单元格右下角&#xff0c;会出现一个黑色的小加号&#xf…

重大更新来袭!!《植物大战僵尸杂交版V2.1+修改器+融合版》

大家好&#xff01;每个软件更新总是令人兴奋不已。前段时间介绍的《植物大战僵尸》系列以其独特的策略玩法和丰富的植物角色&#xff0c;赢得了很多玩家的喜爱。而在今天&#xff0c;这款经典游戏全网最新版本——《植物大战僵尸&#xff1a;杂交版V2.1》正式推出&#xff0c;…

docker 环境下failed to start lsb故障解决

背景&#xff1a;从深信服超融合迁移虚拟机到VMWARE集群后&#xff0c;迁移后的虚拟机 centos 7 运行systemctl start network ,报错 Restarting network (via systemctl): Job for network.service failed. See systemctl status network.service and journalctl -xn for d…

Redis组建哨兵模式

主172.17.60.131 从172.17.60.130、172.17.60.129 redis部署 [rootlocalhost app]# tar xf redis-6.2.9.tar.gz [rootlocalhost app]# cd redis-6.2.9/ [rootlocalhost redis-6.2.9]# make MALLOClibc [rootlocalhost redis-6.2.9]# make install PREFIX/usr/local/redis…

Docker 中查看及修改 Redis 容器密码的实用指南

在使用 Docker 部署 Redis 容器时&#xff0c;有时我们需要查看或修改 Redis 的密码。本文将详细介绍如何在 Docker 中查看和修改 Redis 容器的密码&#xff0c;帮助你更好地管理和维护你的 Redis 实例。 一、查看 Redis 容器密码 通常在启动 Redis 容器时&#xff0c;我们会…

构建LangChain应用程序的示例代码:56、如何实现一个多智能体模拟,其中没有固定的发言顺序。智能体自行决定谁来发言,通过竞价机制实现

多智能体分散式发言人选择 示例展示了如何实现一个多智能体模拟,其中没有固定的发言顺序。智能体自行决定谁来发言,通过竞价机制实现。 我们将在下面的示例中展示一场虚构的总统辩论来演示这一过程。 导入LangChain相关模块 from typing import Callable, Listimport tenac…

正向代理反向代理

nginx的正向代理和反向代理: 正向代理以及缓存配置: 代理:客户端不再是直接访问服务端&#xff0c;通过代理服务器访问服务端。 正向代理&#xff1a;面向客户端&#xff0c;通过代理服务器的ip地址访问目标服务端 服务端只知道代理服务器的地址&#xff0c;真正的客户端ip可以…

【MySQL系列】隐式转换

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

ctfshow web入门 nodejs

web334 有个文件下载之后改后缀为zip加压就可以得到两个文件 一个文件类似于index.php 还有一个就是登录密码登录成功就有flag username:ctfshow password:123456因为 return name!CTFSHOW && item.username name.toUpperCase() && item.password passwor…