Java 编码系列:并发工具类详解

引言

在多线程编程中,除了基本的同步机制外,Java 还提供了丰富的并发工具类,这些工具类可以帮助开发者更高效地管理和协调多线程任务。本文将详细介绍 Executor 框架、CountDownLatchCyclicBarrierSemaphore 等并发工具类的工作原理、使用方法,并结合大厂的最佳实践和底层核心原理,帮助读者深入理解这些工具类的应用。

1. Executor 框架
1.1 基本概念

Executor 框架是 Java 并发库中的一个重要组成部分,它提供了一种将任务提交与任务执行解耦的方式。通过 Executor 框架,可以方便地管理和调度线程,提高程序的性能和可维护性。

1.2 主要接口和实现
  • Executor 接口:最基本的接口,定义了 execute(Runnable command) 方法,用于执行任务。
  • ExecutorService 接口:继承自 Executor 接口,提供了更丰富的功能,如任务提交、关闭和生命周期管理。
  • ThreadPoolExecutor 类ExecutorService 的一个具体实现,提供了线程池的功能。
  • ScheduledExecutorService 接口:继承自 ExecutorService 接口,提供了定时任务和周期任务的执行功能。
  • ScheduledThreadPoolExecutor 类ScheduledExecutorService 的一个具体实现。
1.3 使用方法
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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

        for (int i = 0; i < 10; i++) {
            int taskId = i;
            executor.submit(() -> {
                System.out.println("任务 " + taskId + " 开始执行,线程名: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 执行完毕");
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}
1.4 底层原理
  • 线程池ThreadPoolExecutor 是 ExecutorService 的主要实现类,它通过维护一个线程池来管理线程的创建和销毁。
  • 工作队列:任务提交后会被放入一个工作队列中,线程池中的空闲线程会从队列中取出任务并执行。
  • 拒绝策略:当线程池中的线程数量达到上限且工作队列已满时,新的任务会被拒绝。ThreadPoolExecutor 提供了多种拒绝策略,如 AbortPolicyCallerRunsPolicy 等。
1.5 优缺点
  • 优点
    • 提高了线程的复用率,减少了线程创建和销毁的开销。
    • 提供了丰富的配置选项,可以根据业务需求灵活调整线程池的大小和行为。
    • 支持任务的异步执行和结果返回。
  • 缺点
    • 配置复杂,需要合理设置线程池的参数,否则可能导致性能问题。
2. CountDownLatch
2.1 基本概念

CountDownLatch 是一个同步辅助类,允许一个或多个线程等待其他线程完成操作后再继续执行。它通过一个计数器来实现这一功能,当计数器的值为0时,所有等待的线程将被释放。

2.2 使用方法
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        int numberOfThreads = 3;
        CountDownLatch latch = new CountDownLatch(numberOfThreads);

        for (int i = 0; i < numberOfThreads; i++) {
            int taskId = i;
            new Thread(() -> {
                System.out.println("任务 " + taskId + " 开始执行,线程名: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 执行完毕");
                latch.countDown(); // 减少计数器的值
            }).start();
        }

        latch.await(); // 等待所有任务完成
        System.out.println("所有任务已完成");
    }
}
2.3 底层原理
  • AQS(AbstractQueuedSynchronizer)CountDownLatch 的实现基于 AQS,通过一个 volatile int 变量来管理计数器的值。
  • 同步队列:当计数器的值大于0时,调用 await 方法的线程会被阻塞并加入同步队列,直到计数器的值变为0。
2.4 优缺点
  • 优点
    • 简单易用,适用于一个或多个线程等待其他线程完成任务的场景。
    • 支持超时等待,可以通过 await(long timeout, TimeUnit unit) 方法指定等待时间。
  • 缺点
    • 计数器的值只能递减,不能重置,如果需要重置计数器,需要创建新的 CountDownLatch 实例。
3. CyclicBarrier
3.1 基本概念

CyclicBarrier 是一个同步辅助类,允许一组线程互相等待,直到所有线程都到达一个屏障点。与 CountDownLatch 不同,CyclicBarrier 的计数器可以重置,因此可以重复使用。

3.2 使用方法
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        int numberOfThreads = 3;
        CyclicBarrier barrier = new CyclicBarrier(numberOfThreads, () -> {
            System.out.println("所有任务已完成,执行额外操作");
        });

        for (int i = 0; i < numberOfThreads; i++) {
            int taskId = i;
            new Thread(() -> {
                System.out.println("任务 " + taskId + " 开始执行,线程名: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 执行完毕,等待其他任务");
                try {
                    barrier.await(); // 等待其他任务
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 继续执行");
            }).start();
        }
    }
}
3.3 底层原理
  • AQS(AbstractQueuedSynchronizer)CyclicBarrier 的实现也基于 AQS,通过一个 volatile int 变量来管理计数器的值。
  • 同步队列:当计数器的值大于0时,调用 await 方法的线程会被阻塞并加入同步队列,直到计数器的值变为0。
3.4 优缺点
  • 优点
    • 支持计数器的重置,可以重复使用。
    • 支持屏障动作,可以在所有线程到达屏障点后执行额外的操作。
  • 缺点
    • 如果某个线程在等待过程中被中断或发生异常,会导致其他线程无法继续执行,需要处理 BrokenBarrierException
4. Semaphore
4.1 基本概念

Semaphore 是一个同步辅助类,用于控制同时访问特定资源的线程数量。它通过一个计数器来实现这一功能,当计数器的值大于0时,线程可以获取许可;否则,线程将被阻塞,直到有其他线程释放许可。

4.2 使用方法
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private final Semaphore semaphore = new Semaphore(3); // 最多允许3个线程同时访问

    public void accessResource() {
        try {
            semaphore.acquire();
            System.out.println("线程 " + Thread.currentThread().getName() + " 访问资源");
            Thread.sleep(1000); // 模拟资源访问时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }

    public static void main(String[] args) {
        SemaphoreExample example = new SemaphoreExample();

        for (int i = 0; i < 10; i++) {
            int taskId = i;
            new Thread(() -> {
                example.accessResource();
            }, "Thread-" + taskId).start();
        }
    }
}
4.3 底层原理
  • AQS(AbstractQueuedSynchronizer)Semaphore 的实现也基于 AQS,通过一个 volatile int 变量来管理许可的数量。
  • 同步队列:当许可的数量大于0时,调用 acquire 方法的线程可以获取许可;否则,线程将被阻塞并加入同步队列,直到有其他线程释放许可。
4.4 优缺点
  • 优点
    • 控制同时访问资源的线程数量,避免资源过载。
    • 支持公平和非公平模式,可以根据业务需求选择合适的模式。
  • 缺点
    • 需要手动管理许可的获取和释放,容易出现遗漏。
5. 大厂最佳实践
5.1 阿里巴巴《Java开发手册》
  • 线程池配置:合理配置线程池的大小,避免线程过多导致系统资源耗尽。
  • 任务提交:使用 submit 方法提交任务,以便获取任务的执行结果。
  • 资源管理:使用 try-with-resources 语句管理资源,确保资源在使用后正确释放。
5.2 Google Java Style Guide
  • 异常处理:合理处理线程中的异常,避免未捕获的异常导致线程终止。
  • 资源管理:确保在多线程环境中正确使用锁,避免死锁和数据不一致。
  • 性能优化:合理使用并发工具类,避免过度同步导致性能下降。
5.3 Oracle 官方文档
  • 线程池:根据业务需求选择合适的线程池类型,如固定大小线程池、缓存线程池等。
  • 同步辅助类:合理使用 CountDownLatchCyclicBarrier 和 Semaphore 等同步辅助类,避免多线程环境下的数据不一致和死锁问题。
6. 底层核心原理
6.1 AQS(AbstractQueuedSynchronizer)
  • 状态管理:AQS 使用一个 volatile int state 变量来管理同步状态。
  • FIFO 队列:AQS 使用一个 FIFO 队列来管理等待获取锁或许可的线程。
  • 自定义同步器:AQS 提供了 acquire 和 release 方法,子类可以通过实现这些方法来自定义同步器。
6.2 线程池
  • 线程创建:线程池在初始化时创建一定数量的线程,这些线程会在空闲时等待任务。
  • 任务提交:任务提交后会被放入一个工作队列中,线程池中的空闲线程会从队列中取出任务并执行。
  • 线程回收:当线程池中的线程数量超过核心线程数且空闲时间超过设定值时,多余的线程将被回收。
6.3 同步辅助类
  • 计数器管理CountDownLatch 和 CyclicBarrier 通过一个 volatile int 变量来管理计数器的值。
  • 同步队列:当计数器的值大于0时,调用 await 方法的线程会被阻塞并加入同步队列,直到计数器的值变为0。
  • 许可管理Semaphore 通过一个 volatile int 变量来管理许可的数量,当许可的数量大于0时,调用 acquire 方法的线程可以获取许可;否则,线程将被阻塞并加入同步队列。
7. 示例代码
7.1 Executor 框架
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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

        for (int i = 0; i < 10; i++) {
            int taskId = i;
            executor.submit(() -> {
                System.out.println("任务 " + taskId + " 开始执行,线程名: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 执行完毕");
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}
7.2 CountDownLatch
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        int numberOfThreads = 3;
        CountDownLatch latch = new CountDownLatch(numberOfThreads);

        for (int i = 0; i < numberOfThreads; i++) {
            int taskId = i;
            new Thread(() -> {
                System.out.println("任务 " + taskId + " 开始执行,线程名: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 执行完毕");
                latch.countDown(); // 减少计数器的值
            }).start();
        }

        latch.await(); // 等待所有任务完成
        System.out.println("所有任务已完成");
    }
}
7.3 CyclicBarrier
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        int numberOfThreads = 3;
        CyclicBarrier barrier = new CyclicBarrier(numberOfThreads, () -> {
            System.out.println("所有任务已完成,执行额外操作");
        });

        for (int i = 0; i < numberOfThreads; i++) {
            int taskId = i;
            new Thread(() -> {
                System.out.println("任务 " + taskId + " 开始执行,线程名: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 执行完毕,等待其他任务");
                try {
                    barrier.await(); // 等待其他任务
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 继续执行");
            }).start();
        }
    }
}
7.4 Semaphore
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private final Semaphore semaphore = new Semaphore(3); // 最多允许3个线程同时访问

    public void accessResource() {
        try {
            semaphore.acquire();
            System.out.println("线程 " + Thread.currentThread().getName() + " 访问资源");
            Thread.sleep(1000); // 模拟资源访问时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }

    public static void main(String[] args) {
        SemaphoreExample example = new SemaphoreExample();

        for (int i = 0; i < 10; i++) {
            int taskId = i;
            new Thread(() -> {
                example.accessResource();
            }, "Thread-" + taskId).start();
        }
    }
}
8. 总结

本文详细介绍了 Java 并发编程中的 Executor 框架、CountDownLatchCyclicBarrierSemaphore 等并发工具类的工作原理、使用方法,并结合大厂的最佳实践和底层核心原理,帮助读者深入理解这些工具类的应用。合理地使用并发工具类可以提高程序的性能和可靠性,避免多线程环境下的数据不一致和死锁问题。希望本文对你有所帮助,如果你有任何问题或建议,欢迎留言交流。


希望这篇文章能够满足你的需求,如果有任何进一步的问题或需要更多内容,请随时告诉我!

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

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

相关文章

Linux之我不会

一、常用命令 1.系统管理 1.1 systemctl start | stop | restart | status 服务名 案例实操 1 查看防火墙状态 systemctl status firewalld2 停止防火墙服务 systemctl stop firewalld3 启动防火墙服务 systemctl start firewalld4 重启防火墙服务 systemctl restart f…

Type-C接口相关知识:【总结大全】

Type-c现在非常通用了&#xff0c;所以了解Type-c也变得十分有必要了&#xff0c;还是秉承了解就要了解清楚的原则&#xff0c;我们深入的看看Type-c接口。 Type-c主要是取代上一代Micro usb接口&#xff0c;那么Type-c有什么优点呢&#xff1f; 正反可插&#xff0c;使用时不…

OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【LMS调测】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 基本概念 LMS全称为Lite Memory Sanitizer&#xff0c;是一种实时…

Xcode报错:The request was denied by service delegate (SBMainWorkspace)

Xcode报错&#xff1a;The request was denied by service delegate (SBMainWorkspace) 造成的原因: &#xff08;1&#xff09;新的M2芯片的Mac电脑 (2) 此电脑首次安装启动Xcode的应用程序 (3&#xff09;此电脑未安装Rosetta 解决方法: &#xff08;1&#xff09;打开终端…

传奇GEE引擎版本如何封挂?GEE引擎设置简单的封挂脚本教程

网关参数设置gee引擎封挂脚本 1、打开M2-选项-参数设置-游戏速度 把所有的设置限速关闭 2、打开M2-选项-客户端设置-内挂控制-速度控制&#xff1a;移动速度 攻击速度 魔法速度 设置好参数&#xff0c;一旦设置不要修改 否则封挂网关参数需重新设置 打开M2-选项-功能设置-…

计算机毕业设计 基于Flask+Vue的博客系统 Python毕业设计 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

二、kafka生产与消费全流程

一、使用java代码生产、消费消息 1、生产者 package com.allwe.client.simple;import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.clients.pr…

单通道串口服务器

型号&#xff1a; SG-TCP232-110 功能简介 SG-TCP232-110 是一款用来进行串口数据和网口数据转换的设备。解决普通串口设备在 Internet 上的联网问题。 设备的串口部分提供一个 232 接口和一个 485 接口&#xff0c;两个接口内部连接&#xff0c;同时只能使用一个口工作。 设备…

CVE-2024-46103

前言 CVE-2024-46103 SEMCMS的sql漏洞。 漏洞简介 SEMCMS v4.8中&#xff0c;SEMCMS_Images.php的search参数&#xff0c;以及SEMCMS_Products.php的search参数&#xff0c;存在sql注入漏洞。 &#xff08;这个之前就有两个sql的cve&#xff0c;这次属于是捡漏了&#x1f6…

Linux环境下安装python

Linux 环境下安装python 以下是在Linux环境下安装Python - 3.9.4.tgz的详细步骤&#xff1a;1. 下载Python - 3.9.4.tgz&#xff08;如果未下载&#xff09;2.解压文件3.安装依赖项&#xff08;如果需要&#xff09;4.配置和编译5.安装6.创建一个别名&#xff08;alias&#xf…

Sql Developer日期显示格式设置

默认时间格式显示 设置时间格式&#xff1a;工具->首选项->数据库->NLS->日期格式: DD-MON-RR 修改为: YYYY-MM-DD HH24:MI:SS 设置完格式显示&#xff1a;

JavaEE: 深入探索TCP网络编程的奇妙世界(四)

文章目录 TCP核心机制TCP核心机制四: 滑动窗口为啥要使用滑动窗口?滑动窗口介绍滑动窗口出现丢包咋办? TCP核心机制五: 流量控制 TCP核心机制 上一篇文章 JavaEE: 深入探索TCP网络编程的奇妙世界(三) 书接上文~ TCP核心机制四: 滑动窗口 为啥要使用滑动窗口? 之前我们讨…

计算机网络--HTTP协议

1.TCP,UDP的对比图 TCP:面向连接的,可靠的,字节流服务; UDP:无连接的,不可靠的,数据报服务; 2.补充网络部分的其他知识点 1).复位报文段 在某些特殊条件下&#xff0c; TCP 连接的一端会向另一端发送携带 RST 标志的报文段&#xff0c;即复位报文段&#xff0c;已通知对方…

大数据-146 Apache Kudu 安装运行 Dockerfile 模拟集群 启动测试

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

视觉分析在垃圾检测中的应用

随着城市化进程的加快&#xff0c;垃圾管理成为现代城市面临的重大挑战。有效的垃圾识别和分类不仅能提升环境保护的效率&#xff0c;还能减少资源浪费。基于视觉分析的垃圾识别算法应运而生&#xff0c;为解决这一问题提供了技术支持。 垃圾识别算法的技术实现主要依赖于深度学…

002、视频格式转换

下载地址 http://www.pcfreetime.com/formatfactory/CN/index.html

【C++进阶】AVL树的介绍及实现

【C进阶】AVL树的介绍及实现 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;C&#x1f96d; &#x1f33c;文章目录&#x1f33c; 1. AVL的介绍 2. AVL树的实现 2.1 AVL树的结构 2.2 AVL树的插入 2.2.1 插入一个值的大概过程 2.2.2 …

2024年中国电子学会青少年软件编程(Python)等级考试(二级)核心考点速查卡

考前练习 2024年03月中国电子学会青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;二级&#xff09;答案 解析 2024年06月中国电子学会青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;二级&#xff09;答案 解析 知识点描述 …

C语言题目之单身狗2

文章目录 一、题目二、思路三、代码实现 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、题目 二、思路 第一步 在c语言题目之打印单身狗我们已经讲解了在一组数据中出现一个单身狗的情况&#xff0c;而本道题是出现两个单身狗的情况。根据一个数…

LabVIEW编程能力如何能突飞猛进

要想让LabVIEW编程能力实现突飞猛进&#xff0c;需要采取系统化的学习方法&#xff0c;并结合实际项目进行不断的实践。以下是一些提高LabVIEW编程能力的关键策略&#xff1a; 1. 扎实掌握基础 LabVIEW的编程本质与其他编程语言不同&#xff0c;它是基于图形化的编程方式&…