Java零基础之多线程篇:不得不学的并发工具类!

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

  在现代计算机应用中,多线程编程已经变得越来越重要。但是,多线程编程涉及到同步、互斥、线程安全等复杂的问题。为了更方便地进行并发编程,Java提供了java.util.concurrent包,其中包含了许多并发工具类。这些工具类可以帮助开发人员更高效地处理并发问题。本文将介绍并分析这些并发工具类,并提供相关的应用场景案例和优缺点分析。这些也是在日常开发中会经常使用到的,而且也是提高编程效率的方式之一,这对我们在开发过程中极为有用。

摘要

  本文将介绍java.util.concurrent包中的几个重要的并发工具类,包括ExecutorServiceCountDownLatchCyclicBarrier等。我们将通过源代码解析和具体的Java代码测试用例来说明它们的使用方法和效果。并且,我们还将探讨它们在实际应用中的一些常见场景,并分析它们的优点和缺点。

简介

  Java,它自身就提供了多种并发工具类,用于更高级的并发编程。这些工具类可以帮助开发人员处理线程的并发执行、任务的调度和同步等问题。在java.util.concurrent包中,我们可以找到一些最常用的并发工具类。下面我们将介绍其中的一些,仅供参考:

源代码解析

ExecutorService

  ExecutorService是一个线程池,用于管理和调度多个线程。它提供了提交任务、执行任务和获取任务结果的方法。以下是ExecutorService的代码示例:

package com.example.javase.ms.threadDemo.day8;import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;/*** @Author ms* @Date 2024-04-13 12:45*/
public class ExecutorServiceDemo {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(5);executorService.execute(() -> {// 执行任务的代码});Future<String> future = executorService.submit(() -> {// 执行任务的代码return "Task completed";});try {String result = future.get();// 处理任务的结果} catch (InterruptedException | ExecutionException e) {// 处理异常}executorService.shutdown();}
}

测试结果展示

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

测试代码分析

  根据如上代码作出解析,以便于同学们更好的理解,分析如下:案例代码使用了Java的ExecutorService接口和Executors类来创建一个线程池。然后使用execute方法提交一个Runnable任务,使用submit方法提交一个Callable任务。

  在submit方法中,任务被包装成一个Future对象,可以通过调用get方法来获取任务的返回结果。如果任务还没有完成,get方法会阻塞当前线程直到任务完成。

  在try-catch块中,我们可以对任务的返回结果进行处理,也可以处理可能抛出的InterruptedExceptionExecutionException异常。最后,调用shutdown方法来关闭线程池并释放资源。

  其实呢,这种方式可以更好地管理线程池中的线程,避免了显式创建和销毁线程的开销。同时,可以通过submit方法获取任务的返回结果,在需要等待任务完成的场景下非常有用。

CountDownLatch

  CountDownLatch是一个同步辅助类,用于确保一组线程在某个条件满足之前一直等待。它通过一个计数器来控制等待的线程数量。以下是CountDownLatch的代码示例:

package com.example.javase.ms.threadDemo.day8;import java.util.concurrent.CountDownLatch;/*** @Author ms* @Date 2024-04-13 12:53*/
public class CountDownLatchDemo {public static void main(String[] args) {CountDownLatch latch = new CountDownLatch(3);Thread thread1 = new Thread(() -> {// 执行任务的代码latch.countDown();});Thread thread2 = new Thread(() -> {// 执行任务的代码latch.countDown();});Thread thread3 = new Thread(() -> {// 执行任务的代码latch.countDown();});thread1.start();thread2.start();thread3.start();try {latch.await(); // 等待计数器变为0// 所有线程任务完成后执行的代码} catch (InterruptedException e) {// 处理异常}}
}

测试结果展示

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

测试代码分析

  根据如上代码作出解析,以便于同学们更好的理解,分析如下:上述案例展示了如何使用CountDownLatch实现线程间的同步。首先,我们创建了一个CountDownLatch对象,传入初始计数器的值3。然后,我们创建了3个线程,每个线程执行一些任务,并在任务完成后调用countDown()方法减少计数器的值。接下来,我们通过调用start()方法启动这3个线程。然后,我们调用await()方法使当前线程等待,直到计数器的值变为0。这意味着所有线程的任务已经完成。最后,我们可以在await()方法之后添加代码,当所有线程的任务都完成后,这些代码将被执行。

  如果在await()方法等待过程中发生中断,将抛出InterruptedException异常,我们可以在catch块中处理这个异常。

CyclicBarrier

  CyclicBarrier是一个同步辅助类,用于一组线程互相等待达到一个公共屏障点。它可以用于多线程任务的分阶段处理。以下是CyclicBarrier的代码示例:

package com.example.javase.ms.threadDemo.day8;import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;/*** @Author ms* @Date 2024-04-13 12:56*/
public class CyclicBarrierDemo {public static void main(String[] args) {CyclicBarrier barrier = new CyclicBarrier(3, () -> {// 所有线程达到屏障后执行的代码});Thread thread1 = new Thread(() -> {// 执行任务的代码try {barrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}});Thread thread2 = new Thread(() -> {// 执行任务的代码try {barrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}});Thread thread3 = new Thread(() -> {// 执行任务的代码try {barrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}});thread1.start();thread2.start();thread3.start();}
}

测试结果展示

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

测试代码分析

  根据如上代码作出解析,以便于同学们更好的理解,分析如下:上述案例演示了CyclicBarrier的使用。首先,我们创建一个CyclicBarrier对象,传入3作为参数,表示需要等待的线程数量为3。同时,我们使用lambda表达式创建一个屏障动作,用于在所有线程达到屏障后执行的代码。然后,我们创建了3个线程,并且每个线程都执行了一个任务,然后调用了barrier.await()方法,表示线程到达屏障,并进行等待。当所有线程都到达屏障后,屏障动作将被执行。最后,启动这3个线程,它们将会在到达屏障之后执行屏障动作的代码。

  注意,CyclicBarrier是可重用的,也就是说,当所有线程都到达屏障后,屏障会被重置,线程可以继续重新使用该屏障。

应用场景案例

ExecutorService的应用场景案例

  假设我们需要并发地执行一批任务,并且需要等待所有任务完成后才能进行下一步操作。这时,我们可以使用ExecutorService来方便地管理这些任务的执行和等待。下面是一个使用ExecutorService的应用场景案例:

package com.example.javase.ms.threadDemo.day8;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;/*** @Author ms* @Date 2024-04-13 12:58*/
public class ExecutorServiceTest {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(5);List<Future<Integer>> results = new ArrayList<>();for (int i = 0; i < 10; i++) {final int taskId = i;results.add(executorService.submit(() -> {// 执行任务的代码return taskId;}));}executorService.shutdown();try {executorService.awaitTermination(1, TimeUnit.MINUTES);} catch (InterruptedException e) {// 处理异常}int sum = results.stream().mapToInt(future -> {try {return future.get();} catch (InterruptedException | ExecutionException e) {// 处理异常return 0;}}).sum();System.out.println("Sum of task ids: " + sum);}
}

测试结果展示

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

测试代码分析

  根据如上代码作出解析,以便于同学们更好的理解,分析如下:这段代码使用ExecutorService创建一个线程池,并使用submit方法提交10个任务。每个任务是一个Lambda表达式,该Lambda表达式返回其任务ID。将每个任务的返回结果保存在一个Future对象列表中。使用shutdown方法关闭线程池,并使用awaitTermination方法等待线程池中的任务完成。使用stream流将Future对象转换为任务ID的int值,并求和。最后打印任务ID的总和。

CountDownLatch的应用场景案例

  假设我们需要等待多个子线程完成某个任务,然后再开始执行下一步操作。这时,我们可以使用CountDownLatch来控制等待的线程数量。下面是一个使用CountDownLatch的应用场景案例:

package com.example.javase.ms.threadDemo.day8;import java.util.concurrent.CountDownLatch;/*** @Author ms* @Date 2024-04-13 13:01*/
public class CountDownLatchTest {public static void main(String[] args) {CountDownLatch latch = new CountDownLatch(3);Thread thread1 = new Thread(() -> {// 执行任务的代码latch.countDown();});Thread thread2 = new Thread(() -> {// 执行任务的代码latch.countDown();});Thread thread3 = new Thread(() -> {// 执行任务的代码latch.countDown();});thread1.start();thread2.start();thread3.start();try {latch.await(); // 等待计数器变为0// 所有线程任务完成后执行的代码} catch (InterruptedException e) {// 处理异常}}
}

测试结果展示

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

测试代码分析

  根据如上代码作出解析,以便于同学们更好的理解,分析如下:该代码实现了一个使用CountDownLatch的示例。CountDownLatch是一个同步辅助类,可以用来控制多个线程之间的执行顺序。首先,创建了一个CountDownLatch对象,初始计数器值为3。然后,创建了三个线程(thread1, thread2, thread3),每个线程执行一个任务,并在任务执行完后调用latch.countDown()方法递减计数器。接着,启动三个线程。最后,调用latch.await()方法,该方法会阻塞当前线程,直到计数器变为0。一旦计数器变为0,表示所有线程都执行完任务,才会继续执行后续的代码。需要注意的是,如果在调用latch.await()方法期间,当前线程被中断,则会抛出InterruptedException异常。因此,需要在catch块中处理该异常。

CyclicBarrier的应用场景案例

  假设我们需要将一个复杂的任务分成多个阶段执行,并且需要等待每个阶段的所有线程都完成后再继续执行下一个阶段。这时,我们可以使用CyclicBarrier来同步线程的执行。下面是一个使用CyclicBarrier的应用场景案例:

package com.example.javase.ms.threadDemo.day8;import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;/*** @Author ms* @Date 2024-04-13 13:02*/
public class CyclicBarrierTest {public static void main(String[] args) {CyclicBarrier barrier = new CyclicBarrier(3, () -> {// 所有线程达到屏障后执行的代码});Thread thread1 = new Thread(() -> {// 执行任务的代码try {barrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}});Thread thread2 = new Thread(() -> {// 执行任务的代码try {barrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}});Thread thread3 = new Thread(() -> {// 执行任务的代码try {barrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}});thread1.start();thread2.start();thread3.start();}
}

测试结果展示

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

测试代码分析

  根据如上代码作出解析,以便于同学们更好的理解,分析如下:上述案例使用了Java中的CyclicBarrier类来实现线程的同步等待。

  1. 首先,创建了一个CyclicBarrier对象,传入3作为参数表示需要等待的线程数量。第二个参数是一个Lambda表达式,表示当所有线程达到屏障后执行的代码。

  2. 然后,创建了三个线程,每个线程都执行一个任务。在任务中,先调用barrier.await()方法来等待其他线程达到屏障。

  3. 最后,启动三个线程。

  当三个线程都调用了barrier.await()方法后,它们会被阻塞在该方法处,直到全部线程都到达屏障点,才会继续执行后续代码。

  这样就实现了多个线程的同步等待。

优缺点分析

ExecutorService的优缺点

优点:

  • 可以方便地管理和调度多个线程的执行。
  • 提供了提交任务、执行任务和获取任务结果的方法,使用起来非常灵活。

缺点:

  • 线程池的内部实现比较复杂,可能会造成一定的性能开销。
  • 如果线程池中的线程数量设置不合理,可能会导致资源浪费或性能下降。

CountDownLatch的优缺点

优点:

  • 可以方便地控制等待的线程数量,实现任务的同步执行。
  • 使用简单,代码清晰,适合一些简单的并发场景。

缺点:

  • CountDownLatch只能使用一次,不能重复使用。
  • 如果计数器的初始值设置错误,可能会导致死锁或任务无法正常完成。

CyclicBarrier的优缺点

优点:

  • 可以实现多线程任务的分阶段执行,更灵活地控制线程的同步。
  • 可以重复使用,非常适合一些需要重复执行的场景。

缺点:

  • CyclicBarrier的实现比较复杂,容易出现问题。
  • 如果阻塞的线程数量设置不合理,可能会导致线程无法继续执行或无法正常完成。

类代码方法介绍

ExecutorService

  • execute(Runnable task):提交一个可执行的任务给线程池进行执行。
  • submit(Callable<T> task):提交一个有返回值的任务给线程池进行执行
  • shutdown():开始关闭线程池,不再接受新任务,但会完成已提交的任务。
  • awaitTermination(long timeout, TimeUnit unit):等待线程池中所有的任务都完成执行,或者超过指定的等待时间。

CountDownLatch

  • countDown():当前线程执行此方法时,计数器减一。
  • await():当前线程执行此方法时,会阻塞直到计数器归零。
  • getCount():返回当前计数器的值。

CyclicBarrier

  • await():当前线程执行此方法时,会阻塞直到所有等待的线程都到达屏障点。
  • getNumberWaiting():返回正在等待的线程数量。
  • reset():重置屏障,可以重新使用CyclicBarrier

总结

  本文介绍了Java并发工具类中的ExecutorServiceCountDownLatchCyclicBarrier,并通过源代码示例和应用场景案例展示了它们的使用方法。这些工具类在处理并发问题时提供了强大的支持,使得多线程编程变得更加简单和高效。同时,我们也分析了它们的优缺点,帮助开发者更好地理解和使用这些工具类。

  在使用这些并发工具类时,开发者需要注意它们的使用场景和限制,以及如何合理地配置和使用它们以避免潜在的问题。通过合理地使用这些工具类,可以有效地提高程序的性能和并发处理能力。同时,开发者也应该关注Java并发包中其他的工具类,如SemaphoreBlockingQueue等,以便在不同的并发场景中选择合适的工具。

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

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

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

相关文章

数学建模--智能算法之鱼群算法

目录 核心原理 应用与实现 实现步骤 性能分析与改进 鱼群算法在解决哪些具体优化问题方面表现最佳&#xff1f; 如何根据不同的应用场景调整鱼群算法的参数设置以提高其性能&#xff1f; 鱼群算法与其他群体智能优化算法&#xff08;如遗传算法、粒子群优化&#xff09;…

C++ | Leetcode C++题解之第316题去除重复字母

题目&#xff1a; 题解&#xff1a; class Solution { public:string removeDuplicateLetters(string s) {vector<int> vis(26), num(26);for (char ch : s) {num[ch - a];}string stk;for (char ch : s) {if (!vis[ch - a]) {while (!stk.empty() && stk.back(…

html+css前端作业和平精英2个页面(无js)

htmlcss前端作业和平精英2个页面&#xff08;无js&#xff09;有视频播放器等功能效果 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改…

lvs的dr模式综合实践

目录 ​编辑虚拟机准备工作 ​编辑​编辑​编辑 配置过程 配置client主机 配置router主机 配置lvs主机&#xff08;vip使用环回来创建&#xff09; 配置server1主机&#xff08;vip使用环回来创建&#xff09; 配置server2主机&#xff08;vip使用环回来创建&#xff0…

《数据结构》(C语言版)第1章 绪论(下)

第1章 绪论 1.3 抽象数据类型的表示与实现1.4 算法与算法分析 1.3 抽象数据类型的表示与实现 数据类型 数据类型是一组性质相同的值的集合, 以及定义于这个集合上的一组运算的总称。 抽象数据类型(ADTs: Abstract Data Types) 更高层次的数据抽象。由用户定义&#xff0c;用…

3DM游戏运行库合集离线安装包2024最新版

3DM游戏运行库合集离线安装包是一款由国内最大的游戏玩家论坛社区3DM推出的集成式游戏运行库合集软件&#xff0c;旨在解决玩家在玩游戏时遇到的运行库缺失或错误问题。该软件包含多种常用的系统运行库组件&#xff0c;支持32位和64位操作系统&#xff0c;能够自动识别系统版本…

快速上手AWS cloudfront产品

AWS CloudFront&#xff0c;亚马逊推出的卓越全球内容分发网络服务&#xff0c;专为加速网站内容的极速传输而设计&#xff0c;旨在大幅度削减加载延迟&#xff0c;同时确保内容传递过程中的高度安全性和无懈可击的可靠性。借助CloudFront的强大功能&#xff0c;用户能够轻松实…

腾讯云服务器windows系统如何转linux系统

本人购买了腾讯云服务&#xff0c;进去后发现是windows系统的&#xff0c;有点郁闷&#xff08;使用不习惯&#xff09;&#xff0c;于是就去查查看看能不能将Windows系统转成linux系统&#xff0c;网上也有解决办法&#xff0c;但是貌似跟现在的腾讯云后台不一致&#xff0c;下…

Flink学习之Flink SQL(补)

Flink SQL 1、SQL客户端 1.1 基本使用 启动yarn-session yarn-session.sh -d启动Flink SQL客户端 sql-client.sh--退出客户端 exit;测试 重启SQL客户端之后&#xff0c;需要重新建表 -- 构建Kafka Source -- 无界流 drop table if exists students_kafka_source; CREATE TABL…

软件生命周期(二)

1. 软件生命周期定义 软件生命周期&#xff08;SDLC&#xff09;是软件开始研制到最终废弃不用所经历的各个阶段 – 软件开发模型 2. 瀑布型生命周期模型 瀑布模型规定自上而下&#xff0c;相互衔接的固定次序&#xff0c;如同瀑布流水&#xff0c;逐级下落&#xff0c;具有…

sqli-labs(超详解)——Lass32~Lass38

Lass32&#xff08;宽字节注入&#xff09; 源码 function check_addslashes($string) {$string preg_replace(/. preg_quote(\\) ./, "\\\\\\", $string); //escape any backslash$string preg_replace(/\/i, \\\, $string); …

double类型 精度丢失的问题

前言 精度丢失的问题是在其他计算机语言中也都会出现&#xff0c;float和double类型的数据在执行二进制浮点运算的时候&#xff0c;并没有提供完全精确的结果。产生误差不在于数的大小&#xff0c;而是因为数的精度。 一、double进行运算时,经常出现精度丢失 0.10.2使用计算…

记录一次网关无响应的排查

1. 使用jstack pid > thread.txt 打印进 thread.txt 文件里 去观察线程的状态。 我发现&#xff0c;一个线程在经过 rateliter的prefilter后, 先是调用 consume方法&#xff0c;获取到锁。 接着在执行 jedis的 evalsha命令时 一直卡在socket.read()的状态。 发现jedis官…

软件测试必备技能

在软件测试领域&#xff0c;以下是一些必备的技能和能力&#xff0c;可以帮助你成为一名优秀的软件测试工程师&#xff1a; 1. 测试基础知识&#xff1a; 熟悉软件测试的基本概念、原则和流程&#xff0c;包括不同类型的测试&#xff08;如单元测试、集成测试、系统测试&#…

这几个高级爬虫软件和插件真的强!

亮数据&#xff08;Bright Data&#xff09; 亮数据是一款强大的数据采集工具&#xff0c;以其全球代理IP网络和强大数据采集技术而闻名。它能够轻松采集各种网页数据&#xff0c;包括产品信息、价格、评论和社交媒体数据等。 网站&#xff1a;https://get.brightdata.com/we…

LLM(大语言模型)「Agent」开发教程-LangChain(三)

v1.0官方文档&#xff5c;最新文档 一、LangChain入门开发教程&#xff1a;Model I/O 二、基于LangChain的RAG开发教程 LangChain是一个能够利用大语言模型&#xff08;LLM&#xff0c;Large Language Model&#xff09;能力进行快速应用开发的框架&#xff1a; 高度抽象的组件…

智能仪表板DevExpress Dashboard v24.1 - 新增级联参数过滤

使用DevExpress Analytics Dashboard&#xff0c;再选择合适的UI元素&#xff08;图表、数据透视表、数据卡、计量器、地图和网格&#xff09;&#xff0c;删除相应参数、值和序列的数据字段&#xff0c;就可以轻松地为执行主管和商业用户创建有洞察力、信息丰富的、跨平台和设…

揭秘LoRA:利用深度学习原理在Stable Diffusion中打造完美图像生成的秘密武器

文章目录 引言LoRA的原理LoRA在角色生成中的应用LoRA在风格生成中的应用LoRA在概念生成中的应用LoRA在服装生成中的应用LoRA在物体生成中的应用结论 引言 在生成式人工智能领域&#xff0c;图像生成模型如Stable Diffusion凭借其出色的生成效果和广泛的应用场景&#xff0c;逐…

NVIDIA Triton系列03-开发资源说明

NVIDIA Triton系列03-开发资源说明 大部分要学习 Triton 推理服务器的入门者&#xff0c;都会被搜索引擎或网上文章引导至官方的 https://developer.nvidia.com/nvidia-triton-inference-server 处&#xff08;如下截图&#xff09;&#xff0c;然后从 “Get Started” 直接安…

Google四年推迟两次,Cookie不弃了,但也不藏了

四年两次推迟&#xff0c;这段改变了数字广告生态系统发展的代码&#xff0c;还是被Google保留了下来。2020年&#xff0c;Google第一次提出&#xff0c;将在2022年初结束Cookie的使用&#xff0c;同步推出隐私沙盒计划&#xff1b;2021年6月&#xff0c;Google第一次进行了延迟…