探索并发编程

引言

在现代软件开发中,尤其是面对高性能、高并发需求的应用场景,Java的并发编程能力显得尤为重要。Java提供了丰富的API和框架来支持开发者构建高效、可靠的多线程应用程序。本文将深入探讨Java并发编程的核心概念,重点讲解线程池的使用、Future与Callable接口的高级应用,以及如何通过这些工具提升程序的执行效率和响应性。

 线程池:资源管理的艺术

线程池是Java并发编程中的一个核心组件,它通过复用线程来减少线程创建和销毁的开销,有效控制系统资源。`ExecutorService`接口及其实现类,如`ThreadPoolExecutor`,为管理线程池提供了灵活的机制。

创建线程池:

```java

ExecutorService executor = Executors.newFixedThreadPool(10);


```

上述代码创建了一个固定大小的线程池,池中维持10个线程。根据不同的应用场景,还可以选择`newCachedThreadPool`(灵活扩容缩容)或`newSingleThreadExecutor`(单一工作线程)等策略。

任务提交与执行:

```java

executor.submit(() -> {
    // 任务逻辑
});


```

使用`submit`方法可以提交一个实现了`Runnable`接口的任务。对于需要获取结果的任务,应使用`Callable`接口结合`Future`。

 Future与Callable:异步编程的利器

与`Runnable`接口只能执行无返回值的任务不同,`Callable`接口允许任务有返回值,并且可以抛出异常。配合`Future`接口,可以在任务完成后检索结果或捕获异常,非常适合处理耗时操作而不阻塞主线程的场景。

```java

Future<String> future = executor.submit(() -> {
    Thread.sleep(1000); // 模拟耗时操作
    return "Task Result";
});

try {
    System.out.println("Result: " + future.get()); // 获取结果,此方法会阻塞直到结果可用
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}


```

 异步编程的最佳实践

1. 避免Future.get()的直接阻塞: 使用`get(long timeout, TimeUnit unit)`设定超时时间,或者采用CompletionService来更优雅地处理完成的任务。

2. 资源清理: 使用完毕后,记得关闭线程池以释放资源。
   
   ```java
 

  executor.shutdown();


   ```

3. 异常处理: 在任务执行过程中妥善处理异常,确保不会因为某个任务失败而影响整个线程池的正常运行。

4. 监控与调试: 利用线程池提供的统计信息进行性能监控,如`ThreadPoolExecutor`的`getQueue()`、`getCompletedTaskCount()`等方法。

当然,接下来我将通过三个具体案例进一步阐述Java并发编程中线程池、Future与Callable的实战应用。

### for example 1:使用线程池执行批量任务

这个案例展示如何使用线程池执行一批独立的任务,并在所有任务完成后执行后续操作。```java

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5); // 创建固定大小线程池

        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Executing Task " + taskId + " by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        executor.shutdown(); // 关闭线程池,不再接受新任务
        while (!executor.isTerminated()) {
            // 等待所有任务完成
        }
        System.out.println("All tasks completed");
    }
}


```

### for example 2:利用Future获取异步计算结果

本案例演示如何提交Callable任务至线程池并获取其结果,展示了Future的使用方式。```java

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class FutureCallableExample {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        List<Future<Integer>> results = new ArrayList<>();

        for (int i = 0; i < 3; i++) {
            Callable<Integer> task = () -> {
                Thread.sleep(1000); // 模拟计算
                return i * i;
            };
            Future<Integer> future = executor.submit(task);
            results.add(future);
        }

        for (Future<Integer> future : results) {
            System.out.println("Result: " + future.get()); // 获取并打印结果
        }

        executor.shutdown();
    }
}


```

### for example 3:使用CompletionService优化任务处理

CompletionService结合了ExecutorService和BlockingQueue的优点,它允许我们按照完成的顺序处理任务的结果,而不是提交的顺序。

```java
import java.util.concurrent.*;

public class CompletionServiceExample {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        CompletionService<Integer> completionService = new ExecutorCompletionService<>(executor);

        for (int i = 0; i < 3; i++) {
            final int taskId = i;
            completionService.submit(() -> {
                Thread.sleep((long) (Math.random() * 800)); // 模拟不同长度的任务执行时间
                return taskId * taskId;
            });
        }

        for (int i = 0; i < 3; i++) {
            Future<Integer> result = completionService.take(); // 阻塞等待下一个完成的任务
            System.out.println("Task result: " + result.get());
        }

        executor.shutdown();
    }
}


```

以上三个案例分别展示了线程池的基本使用、通过Future获取异步计算结果,以及如何使用CompletionService来优化异步任务的处理流程。这些技巧在实际开发中能显著提升应用的并发处理能力和响应速度。

### for example 4:实现带超时控制的Future任务

有时候,我们希望对任务执行设置超时限制,以防止因个别任务长时间未完成而导致整个系统挂起。以下是如何使用Future的`get(long timeout, TimeUnit unit)`方法来实现这一需求。```java

import java.util.concurrent.*;

public class FutureTimeoutExample {

    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        Future<String> future = executor.submit(() -> {
            Thread.sleep(5000); // 模拟耗时操作
            return "Task done!";
        });

        try {
            System.out.println("Task result: " + future.get(3, TimeUnit.SECONDS)); // 设置3秒超时
        } catch (TimeoutException e) {
            future.cancel(true); // 超时则取消任务
            System.out.println("Task timed out!");
        }

        executor.shutdownNow(); // 关闭线程池
    }
}


```

### for example 5:线程池的动态调整策略

本案例演示如何根据系统负载动态调整线程池的大小,这里使用`ThreadPoolExecutor`自定义创建,利用其构造函数中的参数实现动态调整。```java

import java.util.concurrent.*;

public class DynamicThreadPoolExample {

    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1, // 核心线程数
                6, // 最大线程数
                1, // 空闲线程存活时间
                TimeUnit.SECONDS, // 时间单位
                new ArrayBlockingQueue<>(3), // 工作队列
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略,直接在调用者线程执行
        );

        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                System.out.println("Executing Task " + taskId + " by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务执行
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        executor.shutdown();
    }
}


```

### for example 6:Callable与Future用于并发数据处理

这个案例通过并行处理数据集合,展示了Callable与Future在数据密集型任务中的应用,利用多线程加速数据处理过程。```java

import java.util.*;
import java.util.concurrent.*;

public class DataProcessingExample {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        List<Integer> data = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<Future<Integer>> futures = new ArrayList<>();

        for (Integer number : data) {
            final int num = number;
            Future<Integer> future = executor.submit(() -> processNumber(num));
            futures.add(future);
        }

        List<Integer> processedData = new ArrayList<>();
        for (Future<Integer> future : futures) {
            processedData.add(future.get()); // 获取并收集处理后的结果
        }

        System.out.println("Processed Data: " + processedData);
        executor.shutdown();
    }

    private static Integer processNumber(Integer number) {
        try {
            Thread.sleep(500); // 模拟耗时处理
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return number * number;
    }
}


```

以上三个额外案例进一步展示了Java并发编程中的一些进阶技巧,包括任务超时处理、线程池动态调整策略,以及如何在数据处理中高效利用Callable与Future。这些技术点在构建高性能、响应迅速的系统时尤为关键。

 结论

Java并发编程是构建高性能服务不可或缺的一部分。通过合理利用线程池、Future与Callable,开发者不仅能提升程序的执行效率,还能增强系统的稳定性和可维护性。掌握这些高级特性,对于应对复杂多变的并发场景至关重要。未来,随着Java生态的不断进化,更多高级并发工具和模式的出现将进一步简化并发编程,提升开发效率和应用性能。

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

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

相关文章

记录踩坑事件 分页查询order by出现重复数据bug

MySQL排序小坑_mysql order by name相同导致排序混乱-CSDN博客 1、问题描述 列表页分页查询出现重复数据。 2、问题排查 排查最终执行sql日志。 select * from tableA where (start_time>2024-04-17 00:00:00) AND (start_time<2024-05-18 00:00:00) ORDER BY sta…

rocketmq 学习二 基本概念

教程&#xff1a;基本概念 | RocketMQ 视频教程 https://www.bilibili.com/video/BV1d5411y7UW?vd_sourcef1bd3b5218c30adf0a002c8c937e0a27 版本&#xff1a;5.0 一 基本概念 1.1 生产者/Producer 1.1.1 定义 消息发布者。是构建并传输消息到服务端的运行实体。…

mac远程桌面连接工具:Microsoft Remote Desktop正式版

Microsoft Remote Desktop 是一款由微软开发的远程桌面控制软件。它允许用户通过互联网连接到远程计算机&#xff0c;从而可以在本地计算机上访问和控制远程计算机的桌面、文件和应用程序。 下载地址&#xff1a;https://www.macz.com/mac/1004.html?idOTI2NjQ5Jl8mMjcuMTg2Lj…

ACM实训

【碎碎念】继续搞习题学习&#xff0c;今天完成第四套的ABCD&#xff0c;为下一周挤出时间复习&#xff0c;加油 Digit Counting 问题 法希姆喜欢解决数学问题。但有时解决所有的数学问题对他来说是一个挑战。所以有时候他会为了解决数学难题而生气。他拿起一支粉笔&#xff…

通过管理系统完成商品属性维护

文章目录 1.数据库表设计1.商品属性表 2.renren-generator生成CRUD1.基本配置检查1.generator.properties2.application.yml 2.启动RenrenGeneratorApplication.java生成CRUD1.启动后访问localhost:812.生成商品属性表的crud 3.将crud代码集成到项目中1.解压&#xff0c;找到ma…

Java日志冲突问题

在今天的 Maven 构建过程中&#xff0c;我遇到了 SLF4J 和 Logback 之间的依赖冲突问题。以下是对这些问题的总结以及相应的解决方案。 问题描述: Maven 构建中 SLF4J 和 Logback 依赖冲突问题总结 日志警告&#xff1a; SLF4J: Class path contains multiple SLF4J binding…

flannel详细介绍

一、前言 Flannel 是一个简单、高效的容器网络解决方案&#xff0c;适用于需要在多个主机上运行容器的场景。它通过虚拟网络技术和 IP 地址管理来实现容器之间的通信和跨主机连接&#xff0c;为容器平台提供了可靠的网络基础设施&#xff0c;flannel有三种模式&#xff0c;分别…

sudo pip3 install rpi_ws281x error: externally-managed-environment

报错 error: externally-managed-environment piraspberrypi:~ $ sudo pip3 install rpi_ws281x error: externally-managed-environment This environment is externally managed ╰─> To install Python packages system-wide, try apt installpython3-xyz, where xyz i…

如何自建谷歌站点?

自建谷歌站点其实是一个相对简单的过程&#xff0c;主要是指创建一个能够被谷歌搜索引擎索引和搜索的网站 首先要做的自然就是选择一个域名&#xff0c;域名基本就相当于你的门牌号了&#xff0c;你得想一个既好记又能代表你网站内容的名字&#xff0c;注册域名可以去很多网站…

【Qt】之【Bug】C2001 常量中有换行符

分析 参考&#xff1a;Qt记录&#xff1a;Qt编程遇C2001错误&#xff0c;提示“常量中有换行符”_qt 常量中有换行符-CSDN博客 原因 字符串中有中文字符 &#xff1a;使用了中文标点符号&#xff01; 解决 中文感叹号改为英文的

基于transformers框架实践Bert系列4-文本相似度

本系列用于Bert模型实践实际场景&#xff0c;分别包括分类器、命名实体识别、选择题、文本摘要等等。&#xff08;关于Bert的结构和详细这里就不做讲解&#xff0c;但了解Bert的基本结构是做实践的基础&#xff0c;因此看本系列之前&#xff0c;最好了解一下transformers和Bert…

RisingWave 用户定义函数 (一) :概览

&#xff5c;作者&#xff1a;王润基 RisingWave Labs 内核开发工程师 用户定义函数&#xff08;User Defined Function&#xff0c;以下简称 UDF&#xff09;是数据系统中的常见功能。它允许用户使用各种语言定义自己的函数&#xff0c;作为内置函数的补充&#xff0c;以实现…

【前端】使用 Canvas 实现贪吃蛇小游戏

使用 Canvas 实现贪吃蛇小游戏 在这篇博客中&#xff0c;我们将介绍如何使用 HTML5 Canvas 和 JavaScript 实现一个简单的贪吃蛇&#xff08;Snake&#xff09;小游戏。这个项目是一个基础的游戏开发练习&#xff0c;它可以帮助你理解如何在 Canvas 上绘图、如何处理用户输入以…

【九十三】【算法分析与设计】719. 找出第 K 小的数对距离,N 台电脑的最长时间,二分答案法

719. 找出第 K 小的数对距离 - 力扣&#xff08;LeetCode&#xff09; 数对 (a,b) 由整数 a 和 b 组成&#xff0c;其数对距离定义为 a 和 b 的绝对差值。 给你一个整数数组 nums 和一个整数 k &#xff0c;数对由 nums[i] 和 nums[j] 组成且满足 0 < i < j < nums.le…

校园网拨号上网环境下多开虚拟机,实现宿主机与虚拟机互通,并访问外部网络

校园网某些登录客户端只允许同一时间一台设备登录&#xff0c;因此必须使用NAT模式共享宿主机的真实IP&#xff0c;相当于访问外网时只使用宿主机IP&#xff0c;此方式通过虚拟网卡与物理网卡之间的数据转发实现访问外网及互通 经验证&#xff0c;将centos的物理地址与主机物理…

UMPNet: Universal Manipulation Policy Network for Articulated Objects

1. 摘要 UMPNet是一个基于图像的策略网络&#xff0c;能够推理用于操纵铰接物体的闭环动作序列。该策略支持6DoF动作表示和可变长度轨迹。 为处理多种类的物体&#xff0c;该策略从不同的铰接结构中学习&#xff0c;并泛化到未见过的物体或类别上。该策略是以自监督探索的方式…

利用Python队列生产者消费者模式构建高效爬虫

目录 一、引言 二、生产者消费者模式概述 三、Python中的队列实现 四、生产者消费者模式在爬虫中的应用 五、实例分析 生产者类&#xff08;Producer&#xff09; 消费者类&#xff08;Consumer&#xff09; 主程序 六、总结 一、引言 随着互联网的发展&#xff0c;信…

css使用clip-path裁剪出不规则图形并绑定点击事件

点击图片的红色区域触发事件 点击图片黑色不触发点击事件&#xff0c;代码演示效果如下&#xff1a; 代码演示效果 1.png&#xff08;尺寸 200*470&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><…

2025第十届美陈展

展位又遭疯抢&#xff01;2025第十届美陈展释放“无界之美” 美是全球通用的语言&#xff0c;人类对美的追求始终如一&#xff0c;大众审美在经历了时代的变迁后开始趋同&#xff0c;东方文明深处的美学经济开始崛起。 在如今商业迈入存量阶段&#xff0c;以品牌为突破口打造…

抽象工厂模式(AbstractFactoryPattern)

文章目录 1.抽象工厂模式定义2.UML类图3.抽象工厂模式具体实现工厂模式实现单一产品族抽象工厂实现多产品族产品类工厂类使用 4.抽象工厂模式优缺点 1.抽象工厂模式定义 提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们具体的类。 工厂方法模式是单一产…