java-07 多线程-并发编程(原子变量、CountDownLatch、Future和CompletableFuture、volatile)

  并发编程是指在一个程序中同时执行多个任务或线程。这通常涉及到多线程编程、线程同步、并发容器等技术。这些技术可以用来解决多线程环境中的问题,如线程安全、资源竞争、死锁等问题。在实际的Java并发编程中,还需要考虑到线程池、Future、Callable、ExecutorService等概念。

在另一篇文章介绍了多线程、进程、并发、并行等基本概念,并分析了线程安全问题产生的原因,同时也整理了线程实现的4种方式,并做了对比,请参考 java-06 多线程-4种实现方式

如果你觉得我分享的内容或者我的努力对你有帮助,或者你只是想表达对我的支持和鼓励,请考虑给我点赞、评论、收藏。您的鼓励是我前进的动力,让我感到非常感激。

文章目录

  • 1 线程同步
    • 1.1 锁
    • 1.2 原子变量
    • 1.3 ThreadLocal
    • 1.4 CountDownLatch
    • 1.5 Future 和 CompletableFuture
    • 1.6 volatile

1 线程同步

1.1 锁

java-07 多线程-并发编程(锁)

1.2 原子变量

除了 StampedLock 中的乐观读锁,java.util.concurrent.atomic 包下面 AtomicInteger、AtomicLong、AtomicIntegerArray、AtomicReference 等原子变量类也是基于乐观锁的思想实现的。

不过普通的 AtomicInteger 可能会存在 ABA 问题,此时可以使用 AtomicStampedReference,它内部除了一个对象引用,还维护了一个可以自动更新的整数,通过标识版本来避免 ABA 问题。

AtomicInteger 的基本使用示例:

import java.util.concurrent.atomic.AtomicInteger;public class Main {private static final AtomicInteger counter = new AtomicInteger(0);public static void main(String[] args) {Runnable incrementTask = () -> {for (int i = 0; i < 10000; i++) {counter.incrementAndGet();}};Thread thread1 = new Thread(incrementTask);Thread thread2 = new Thread(incrementTask);thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final counter value: " + counter.get());}
}

AtomicReference 的基本使用示例:

import java.util.concurrent.atomic.AtomicReference;public class Main {private static final AtomicReference<Integer> counterRef = new AtomicReference<>(0);public static void main(String[] args) {Runnable incrementTask = () -> {for (int i = 0; i < 10000; i++) {while (true) {Integer current = counterRef.get();Integer updated = current + 1;if (counterRef.compareAndSet(current, updated)) {break;}}}};Thread thread1 = new Thread(incrementTask);Thread thread2 = new Thread(incrementTask);thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final counter value: " + counterRef.get());}
}

1.3 ThreadLocal

1.4 CountDownLatch

CountDownLatch 是一个同步辅助类,它允许一个或多个线程等待其他线程完成操作。CountDownLatch 通过一个计数器来实现一个线程等待其他线程完成某个操作,当计数器的值减为零时,等待的线程被释放。

CountDownLatch 主要提供了以下方法:

  • CountDownLatch(int count):构造方法,用于初始化计数器,指定计数器的初始值为 count。
  • void await() throws InterruptedException:当调用线程调用此方法时,它会一直等待,直到计数器减为零。如果计数器不为零,线程将被阻塞。
  • boolean await(long timeout, TimeUnit unit) throws InterruptedException:在指定的时间内等待计数器减为零,如果在指定时间内计数器未减至零,线程将被唤醒。
  • void countDown():每个被等待的线程执行完任务后,都应该调用此方法来减小计数器的值。

以下是一个 CountDownLatch 的简单的示例:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Main {public static void main(String[] args) throws InterruptedException {ExecutorService es = Executors.newFixedThreadPool(10);CountDownLatch latch = new CountDownLatch(10);Runnable task = () -> {System.out.println("task");latch.countDown();};long begin = System.currentTimeMillis();for (int i = 0; i < 10; i++) {es.submit(task);}latch.await();long end = System.currentTimeMillis();System.out.println("time = " + (end - begin));}
}

1.5 Future 和 CompletableFuture

Future 是一个接口,允许我们提交一个任务给线程池或其他异步执行机制,并且在未来获取该任务的结果。它通常用于处理耗时的操作,以便不阻塞主线程,从而提高程序的性能和响应性。

Future 接口相关方法:

  • get():用来获取异步任务的结果,如果任务尚未完成,调用 get() 将会阻塞当前线程,直到任务完成并返回结果。
  • isDone():用来检查异步任务是否已经完成,如果任务已经完成,它将返回 true,否则返回 false。
  • cancel(boolean mayInterruptIfRunning):用于取消异步任务的执行,mayInterruptIfRunning 参数用于指定是否应该中断正在执行的任务。如果任务成功取消,get() 方法将会抛出 CancellationException。

Future 接口通常通过 ExecutorService 接口的实现来使用,ExecutorService 提供了一种提交任务并获取 Future 的方式,从而管理线程池中的任务。

此外,Java 8 中还引入了 CompletableFuture 类,它实现了 Future 接口并提供了更丰富的功能,包括支持函数式编程、组合多个异步任务等。

Future 异步执行任务示例:

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;class Solution {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);Future<Integer> future = executor.submit(() -> {Thread.sleep(2000);  // 模拟一个耗时操作return 42;});try {System.out.println("等待任务完成...");Integer result = future.get();System.out.println("任务完成,结果为:" + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}executor.shutdown();}
}

CompletableFuture 异步执行任务示例:
分批处理数据

批量删除数据

@Async("commonCmdbExecutor")
public CompletableFuture<CmdbResultVo> multiDeleteObjInstance(CmdbDeleteObjInstanceReqVo body,CountDownLatch latch) {String url = cmdbHost + CmdbConstants.MULTI_DELETE_OBJ_INSTANCE_URL;ResponseEntity<CmdbResultVo> exchange = null;try {exchange = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<Object>(body, new HttpHeaders()),CmdbResultVo.class);} catch (Exception e) {LOG.error("delete data error", e);} finally {latch.countDown();}return exchange == null ? null : CompletableFuture.completedFuture(exchange.getBody());
}public int deleteCmdbDataAsync(String objCode, List<String> ids) {int groupQty = ids.size() / DELETE_MAX_SIZE;int resultCode = 1;CountDownLatch latch = new CountDownLatch(groupQty + 1);List<CompletableFuture<CmdbResultVo>> futures = new CopyOnWriteArrayList<>();for (int i = 0; i <= groupQty; i++) {CmdbDeleteObjInstanceReqVo deleteBody = new CmdbDeleteObjInstanceReqVo();deleteBody.setObjCode(objCode);List<String> curGroup = getCurGroup(i, DELETE_MAX_SIZE, ids);deleteBody.setInstanceIdList(curGroup);CompletableFuture<CmdbResultVo> cmdbResultVoCompletableFuture =cmdbClient.multiDeleteObjInstance(deleteBody, latch);futures.add(cmdbResultVoCompletableFuture);}try {latch.await(3, TimeUnit.MINUTES);} catch (InterruptedException e) {LOG.error("InterruptedException:", e);Thread.currentThread().interrupt();} catch (Exception e) {LOG.error("Exception:", e);}for (CompletableFuture<CmdbResultVo> future : futures) {try {CmdbResultVo response = future.get();if (response.getResultCode() == 0) {resultCode = 0;}} catch (Exception e) {LOG.error("Exception:", e);}}return resultCode;
}

批量更新数据

    @Async("commonCmdbExecutor")public <T> CompletableFuture<CmdbResultVo> multiUpdateObjInstanceAsync(CmdbUpdateObjInstanceReqVo<T> body,CountDownLatch latch) {String url = cmdbHost + CmdbConstants.MULTI_UPDATE_OBJ_INSTANCE_URL;ResponseEntity<CmdbResultVo> exchange = null;try {exchange = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<Object>(body, new HttpHeaders()),CmdbResultVo.class);} catch (Exception e) {LOG.error("update data error", e);} finally {latch.countDown();}return exchange == null ? null : CompletableFuture.completedFuture(exchange.getBody());}

1.6 volatile

volatile 关键字主要有两层语义:

  • 保证多线程环境下共享变量操作的可见性:参考 Java 内存模型(JMM)中先行发生(Happens-Before)原则对 volatile 变量规则的描述,对于一个 volatile 变量,如果对于这个变量的写操作先行发生于这个变量的读操作,那么这个写操作所产的影响对于后续的读操作是可见的。

  • 禁止指令重排序:编译器在编译时会在生成的字节码中插入特定的内存屏障指令,确保在 volatile 变量读写操作前后的代码不会被重排序。具体来说,会在 volatile 变量写操作之后,读操作之前插入屏障,因此执行到 volatile 变量读写操作时,前面的操作一定已经执行完成,后面的操作一定还未开始。
    voliatile有三大特性:

  1. 保证可见性。
  2. 不保证原子性。
  3. 禁止指令重排。

因此,voliatile解决不了线程安全问题

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

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

相关文章

与 MySQL 建立连接

命令行连接 MySQL 前面介绍了在 Windows 下安装最新版 MySQL 初始化安装步骤&#xff0c;启动 MySQL 服务&#xff0c;记录的初始密码可用于 “root” 账户登录进行相关操作&#xff0c;Windows 和 Linux 命令行操作步骤一样: 上图为 MySQL 的初始密码。在 Windows 下打开 CMD …

EdgeNAT: 高效边缘检测的 Transformer

EdgeNAT: Transformer for Efficient Edge Detection 介绍了一种名为EdgeNAT的基于Transformer的边缘检测方法。 1. 背景与动机 EdgeNAT预测结果示例。(a, b):来自BSDS500的数据集的输入图像。(c, d):对应的真实标签。(e, f):由EdgeNAT检测到的边缘。(e)显示了由于颜色变化…

小学期中考试老师怎么发成绩

随着期中考试的落幕&#xff0c;老师们面临着一项既耗时又易出错的任务——发布成绩。传统的手动统计和通知方式不仅效率低下&#xff0c;还容易出错。现在&#xff0c;有了一种新的在线平台&#xff0c;可以帮助老师们简化这一流程。 这个平台叫做“易查分”&#xff0c;它是一…

【LLM】Agent在智能客服的实践(AI agent、记忆、快捷回复 | ReAct)

note 内容概况&#xff1a;结合京粉app学习agent的实践 Agent架构&#xff1a;通过模型训练提升LLM识别工具的准确性&#xff1b;设计可扩展并安全可控的agent架构扩展业务能力。记忆&#xff1a;多轮对话应用中如何组织、存储和检索记忆来提升大模型对用户的理解。快捷回复&…

Prescan中的缓和曲线道路spiral road

我主要是针对城市道路作设计&#xff0c;所以主要依据参考&#xff1a;城市道路工程设计规范 CJJ37 -2012 城市道路工程设计规范CJJ37-2012(2016年版) (soujianzhu.cn) 道路的平面线形主要包括直线和平曲线两种形式。直线的几何形状相对固定&#xff0c;缺乏灵活性&#xff0…

水深探测仪的作用和使用方法

在水域救援的行动里&#xff0c;救援人员时刻面临着复杂多变、充满未知的水域状况。当接到救援任务奔赴现场&#xff0c;那片需要涉足的水域就像一个神秘莫测的异世界&#xff0c;挑战着所有人的认知与勇气。 水深探测仪作为一种专用于测量水域深度的设备&#xff0c;通过声波和…

用户和组管理

用户管理 用户管理包括创建用户、修改用户属性、删除用户等操作。 创建用户 使用 useradd 命令可以创建新用户。 格式&#xff1a;useradd [选项] username 步骤1&#xff1a;创建新用户 useradd tom 步骤 2: 设置用户密码 新用户创建后&#xff0c;需要设置一个密码才能…

No.15 笔记 | CSRF 跨站请求伪造

目录 一、基础知识 &#xff08;一&#xff09;cookie 和 session、同源策略 &#xff08;二&#xff09;CSRF 原理 二、CSRF 类型 &#xff08;一&#xff09;GET 类型 &#xff08;二&#xff09;POST 类型 三、CSRF 实例讲解 &#xff08;一&#xff09;真实案例 &am…

springboot如何自动生成mybatis映射文件、dao、pojo层文件?

背景&#xff1a;以前一直是直接cv一个项目中现成的xml文件&#xff0c;然后再去自己配置mapper等数据。自己准备做一个单独的例子试一下。 步骤1&#xff1a;在pom.xml文件中插入mybatis-generator插件&#xff0c;这里选的版本是1.3.2&#xff0c;然后指定的generator文件是在…

一种用于超稳激光的数字控制锁频电路

摘要 超稳激光具有超高的频率稳定度和极窄线宽等优点&#xff0c;广泛应用于各种精密测量物理实验。为了确保不引入额外开关噪声&#xff0c;其频率锁定电路通常采用模拟电路实现&#xff0c;但是模拟控制电路存在锁定参数调节不方便、难以实现自动锁定和远程控制等方面的不足。…

端口冲突的解决方案以及SpringBoot自动检测可用端口demo

端口冲突的解决方案 端口冲突通常发生在尝试运行两个或多个应用程序或服务时&#xff0c;它们尝试使用同一个端口号&#xff0c;导致系统无法正确分配资源。 各种端口错误 你是否遇到过下面这些报错信息呢&#xff1f; Windows 系统报错&#xff1a; 系统错误 1004 套接字操作…

自适应气泡小计

View 代码 <div class"mas-view"><div class"m-2"><span>新新消息消新消息消息新消息新消息新消息新消息新消息新消息新消息新消息新息</span></div></div>CSS 样式 .mas-view{width: 100%;height: auto;border: 1px…

【unity进阶知识9】序列化字典,场景,vector,color,Quaternion

文章目录 前言一、可序列化字典类普通字典简单的使用可序列化字典简单的使用 二、序列化场景三、序列化vector四、序列化color五、序列化旋转Quaternion完结 前言 自定义序列化的主要原因&#xff1a; 可读性&#xff1a;使数据结构更清晰&#xff0c;便于理解和维护。优化 I…

Kubernetes--深入理解Pod资源管理

文章目录 kubectl --helpapi-resourcesapi-versionskubectl explain ... API资源资源规范PodServiceConfigMapSecret 显示资源删除资源详细描述RESTful API Pod资源管理Pod的核心概念Pod资源配置了解Pod运行状况Kubectl get pods xxxxkubectl describe pods xxxkubectl logs -f…

数据分析:锚定手工赛道,小红书爆文内容解析

导语 高倍速增长&#xff0c;近年手工赛道趋势有目共睹&#xff0c;可谓小红书长盛不衰的内容。 相关话题常年位居热门话题榜TOP30&#xff0c;浏览量超百亿&#xff0c;话题下更是诞生了很多大爆文。小编就来带大家探索下&#xff0c;为何小红书“手工”赛道会如此火热&…

高校党费收缴系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;党费收缴管理&#xff0c;论坛信息管理&#xff0c;新闻动态管理&#xff0c;公告管理&#xff0c;基础数据管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;公告&…

Spring Cloud 配置中心详解:微服务动态读取与案例示范

在微服务架构中&#xff0c;每个微服务往往都有其独立的配置&#xff0c;这些配置可能会根据环境的不同&#xff08;开发、测试、生产&#xff09;进行调整和变化。Spring Cloud 配置中心提供了一种集中化管理和动态更新微服务配置的解决方案。在本文中&#xff0c;我们将详细介…

SpringSecurity(三)——自定义优化器

在SpringSecurity中&#xff0c;如果我们在认证或者授权的过程中出现了异常会被ExceptionTranslationFilter捕 获到。在ExceptionTranslationFilter中会去判断是认证失败还是授权失败出现的异常。 一、自定义验证异常类 创建exception包&#xff0c;在exception包下创建自定义…

centos7.9升级rockylinux8.8

前言 查看centos的版本 &#xff0c;我这台服务器是虚拟机,下面都是模拟实验 升级前一定要把服务器上配置文件&#xff0c;数据等进行备份 [rootlocalhost ~]#cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootlocalhost ~]#uname -a Linux jenkins_ser…

爱吃蟠桃的孙悟空

文章目录 1. 题目描述2. 实现3. 整体思路4. 函数定义及参数解释5.二分查找过程6.主函数部分 1. 题目描述 2. 实现 #include <iostream> #include <vector> #include <algorithm>using namespace std;int findMinEatingSpeed(vector<int>& piles, …