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.mfbz.cn/a/777356.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaWeb程序设计】JSP编程II

目录 一、输入并运行下面的import_test.jsp页面 1.1 代码运行结果 1.2 修改编码之后的运行结果 二、errorPage属性和isErrorPage属性的使用 2.1 下面的hello.jsp页面执行时将抛出一个异常&#xff0c;它指定了错误处理页面为errorHandler.jsp。 2.1.2 运行截图 2.2 下面…

压测工具---Ultron

压测工具&#xff1a;Ultron 类型&#xff1a;接口级和全链路 接口级 对于接口级别的压测我们可以进行 http接口压测、thrift压测、redis压测、kafka压测、DDMQ压测、MySQL压测等&#xff0c;选对对应的业务线、选择好压测执行的时间和轮数就可以执行压测操作了 全链路 对…

Java新特性梳理——Java15

highlight: xcode theme: vuepress 概述 2020 年 9 月 15 日&#xff0c;Java 15 正式发布&#xff0c;(风平浪静的一个版本)共有 14 个 JEP&#xff0c;是时间驱动形式发布的第六个版本。相关文档&#xff1a;https://openjdk.java.net/projects/jdk/15/ 语法层面变化 密封类 …

【机器学习】基于密度的聚类算法:DBSCAN详解

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 基于密度的聚类算法&#xff1a;DBSCAN详解引言DBSCAN的基本概念点的分类聚类过…

JVM原理(十七):JVM虚拟机即时编译器详解

编译器无论在何时、在何种状态下把Class文件转换成与本地基础设施相关的二进制机器码&#xff0c;他都可以视为整个编译过程的后端。 后端编译器编译性能的好坏、代码优化质量的高低却是衡量一款商用虛拟机优秀与否的关键指标之一。 1. 即时编译器 即时编译器是一个把Java的…

19.【C语言】初识指针(重难点)

内存&#xff1a;所有程序的运行在内存中 用Cheat Engine查看任意程序的内存(16进制&#xff09;&#xff1a; 显示大量的数据 想要定位某个数字 &#xff0c;需要知道地址(类比二维坐标) 如F8的地址为00BCB90008,所以是00BCB908(偏移) ctrlG 则有 内存单元的说明&#xff1…

动态颤抖的眼睛效果404页面源码

动态颤抖的眼睛效果404页面源码&#xff0c; 源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 动态颤抖的眼睛效果404页面源码

Portainer 是一个开源的容器管理平台-非常直观好用的Docker图形化项目

在这个容器化技术大行其道的时代&#xff0c;Docker和Kubernetes几乎成了技术圈的新宠。可是管理起容器来&#xff0c;有时候还是有点头大。命令行操作对于某些小伙伴来说&#xff0c;可能还是有点不太友好。 今天开源君分享一个叫 Portainer 的开源项目&#xff0c;一个用来简…

AI大模型时代的存储发展趋势

从2022年下半年&#xff0c;大模型和AIGC这两个词变得极其火热&#xff0c;而GPU的市场也是一卡难求。对于这种迷乱和火热&#xff0c;让我想起了当年的比特币挖矿和IPFS。似乎世界一年一个新风口&#xff0c;比特币、元宇宙、NFT、AIGC&#xff0c;金钱永不眠&#xff0c;IT炒…

【React】React18 Hooks 之 useReducer

目录 useReducer案例1&#xff1a;useReducer不带初始化函数案例2&#xff1a;useReducer带初始化函数注意事项1&#xff1a;dispatch函数不会改变正在运行的代码的状态注意事项2&#xff1a;获取dispatch函数触发后 JavaScript 变量的值注意事项3&#xff1a;触发了reducer&am…

【MotionCap】pycharm 远程在wsl2 ubuntu20.04中root的miniconda3环境

pycharm wsl2 链接到pycharmsbin 都能看到内容,/root 下内容赋予了zhangbin 所有,pycharm还是看不到/root 下内容。sudo 安装了miniconda3 引发了这些问题 由于是在 root 用户安装的miniconda3 所以安装路径在/root/miniconda3 里 这导致了环境也是root用户的,会触发告警 WA…

Xilinx原语

1. 原语介绍 原语是 Xilinx 器件底层硬件中的功能模块&#xff0c;它使用专用的资源来实现一系列的功能。相比于 IP 核&#xff0c;原语的调用方法更简单&#xff0c;但是一般只用于实现一些简单的功能。本章主要用到了 BUFG、 BUFIO、 IDDR、 ODDR、IDELAYE2 和 IDELAYCTRL。…

14-29 剑和诗人3 – 利用知识图谱增强 LLM 推理能力

知识图谱提供了一种结构化的方式来表示现实世界的事实及其关系。通过将知识图谱整合到大型语言模型中&#xff0c;我们可以增强它们的事实知识和推理能力。让我们探索如何实现这一点。 知识图谱构建 在利用知识图谱进行语言模型增强之前&#xff0c;我们需要从可靠的来源构建…

AIGC | 为机器学习工作站安装NVIDIA 4070 Ti Super显卡驱动

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路 ] 0x00 前言简述 话接上篇《AIGC | Ubuntu24.04桌面版安装后必要配置》文章&#xff0c;作为作者进行机器学习的基础篇&#xff08;筑基期&#xff09;&#xff0c;后续将主要介绍机器学习环境之如何…

springboot+vue+mybatis图书馆借阅管理系统+PPT+论文+讲解+售后

21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&#xff0c;使信息存储达到…

项目实战--Spring Boot与PageHelper的集成及线程污染解决

一、PageHelper使用背景 公司要做个简单管理系统&#xff0c;要我搭建Spring BootMyBatisPageHelperRedis的项目框架然后交i给实习生来开发。这个其实很简单&#xff0c;但是遇到搭建和使用过程中PageHelper有好多小坑&#xff0c;就记录一下&#xff0c;避免再踩。 版本选择&…

hdu物联网硬件实验2 GPIO亮灯

学院 班级 学号 姓名 日期 成绩 实验题目 GPIO亮灯 实验目的 点亮三个灯闪烁频率为一秒 硬件原理 无 关键代码及注释 const int ledPin1 GREEN_LED; // the number of the LED pin const int ledPin2 YELLOW_LED; const int ledPin3 RED…

Java - JDK17语法新增特性(如果想知道Java - JDK17语法新增常见的特性的知识点,那么只看这一篇就足够了!)

前言&#xff1a;Java在2021年发布了最新的长期支持版本&#xff1a;JDK 17。这个版本引入了许多新的语法特性&#xff0c;提升了开发效率和代码可读性。本文将简要介绍一些常见的新特性&#xff0c;帮助开发者快速掌握并应用于实际开发中。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨…

Mysql笔记-v2【7月5日更新】

零、 help、\h、? 调出帮助 mysql> \hFor information about MySQL products and services, visit:http://www.mysql.com/ For developer information, including the MySQL Reference Manual, visit:http://dev.mysql.com/ To buy MySQL Enterprise support, training, …

深入分析 Android BroadcastReceiver (八)

文章目录 深入分析 Android BroadcastReceiver (八)1. 系统与自定义实现1.1 系统广播机制1.1.1 系统广播的实现原理1.1.2 系统广播的源码分析 1.2 自定义广播机制1.2.1 自定义广播的实现步骤1.2.2 自定义广播的源码分析 2. 广播机制设计的初衷与优势2.1 设计初衷2.2 优势 3. 总…