突破瓶颈:Java并发编程的最佳实践与技巧,你了解了吗?

在这里插入图片描述

文章目录

    • 1 什么是 Executor 和 ExecutorService ?这两个接口有什么区别?
    • 2 java.util.concurrent 标准库中 ExecutorService 的可用实现是什么 ?
    • 3 什么是 Java 内存模型( JMM )?描述下其目的和基本思想
    • 4 JMM 对添加了 final 修饰符的类的字段有什么特殊保证 ?

1 什么是 Executor 和 ExecutorService ?这两个接口有什么区别?

ExecutorExecutorService 是用于处理并发任务的两个接口。

Executor 主要用于基本的任务提交,适用于简单的线程管理需求,而 ExecutorService 提供了更多的功能,适用于需要更复杂的任务控制和线程管理的场景。

Executor 是一个简单的接口,它只定义了一个方法 execute(Runnable command),用于执行 Runnable 对象,这个方法将 Runnable 对象提交给执行器,然后执行器在适当的线程上运行这个任务。

// 使用一个固定大小的线程池来执行任务
Executor executor = Executors.newFixedThreadPool(10);
executor.execute(() -> System.out.println("任务运行ing"));

ExecutorService 继承自 Executor,提供了更多的功能,它允许在执行任务时进行更多的控制和管理,比如提交 Callable 任务、取消任务和关闭执行器等。ExecutorService 提供的方法包括 submit() 用于提交任务并获得结果,shutdown() 用于平稳关闭执行器等。

ExecutorService executorService = Executors.newFixedThreadPool(10);
// submit() 方法提交了一个 Callable 任务,并返回一个 Future 对象,用于获取任务的结果
Future<Integer> future = executorService.submit(() -> {// 任务逻辑return 123;
});
// 用于关闭执行器,停止接受新任务并在所有已提交任务完成后关闭线程池
executorService.shutdown();

2 java.util.concurrent 标准库中 ExecutorService 的可用实现是什么 ?

ExecutorService 提供了多种实现,每种实现都有其特定的用途和特点,常见的实现包括 ThreadPoolExecutorScheduledThreadPoolExecutorForkJoinPool

ThreadPoolExecutor 是最基础的实现,它通过维护一个线程池来处理任务。可以创建固定大小的线程池,也可以设置线程池的最大和最小线程数。

使用 Executors.newFixedThreadPool(int nThreads) 方法创建一个固定线程数的线程池:

ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(() -> System.out.println("任务执行ed"));

ScheduledThreadPoolExecutor 扩展了 ThreadPoolExecutor,支持任务的定时和周期性执行。

使用 Executors.newScheduledThreadPool(int corePoolSize) 可以创建一个支持定时任务的线程池:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
scheduler.scheduleAtFixedRate(() -> System.out.println("定时任务"), 0, 1, TimeUnit.SECONDS);

ForkJoinPool 专注于大规模并行计算,适用于分而治之的任务模型,它特别适合处理递归任务,可以高效地将任务分解成多个子任务,然后将结果合并。

使用 ForkJoinPool 可以执行分解任务的操作:

ForkJoinPool forkJoinPool = new ForkJoinPool();
forkJoinPool.submit(() -> {// 递归任务逻辑
}).join();

3 什么是 Java 内存模型( JMM )?描述下其目的和基本思想

Java 内存模型(JMM)可以比喻成一个图书馆的借书系统。这个系统的目的是确保所有的借书和还书记录在所有的图书馆分馆之间都是一致的。无论你在哪个分馆借书或还书,系统都会确保你得到的是最新的、准确的书籍记录。

Java 内存模型(JMM)定义了 Java 程序中线程如何与内存进行交互的规则,它的主要目的是确保多线程环境下的程序行为是可预测的,避免由于线程间的并发访问导致的不一致性和不可预期的错误。

JMM 主要关注两个方面:内存可见性和指令重排序。

内存可见性就像图书馆的借书记录需要在所有分馆同步一样,JMM 确保当一个线程修改了共享数据,其他线程能及时看到这个修改。

内存可见性指的是当一个线程修改了共享变量的值,其他线程能够及时看到这个变化。为了保证这一点,JMM 规定了在不同线程之间的数据同步必须通过特定的操作,比如使用 synchronized 关键字或 volatile 关键字。

使用 synchronized 能够确保在进入一个同步块时,所有之前对共享变量的修改对当前线程是可见的;同样,当线程退出同步块时,对共享变量的修改也会被及时刷新到主内存中。

private int counter = 0;public synchronized void increment() {counter++;
}public synchronized int getCounter() {return counter;
}

指令重排序就像图书馆系统需要确保借书和还书的记录按正确的顺序处理。

指令重排序是指编译器或处理器可能会对程序中的指令进行重新排列,以提高性能。虽然这种优化对于单线程程序通常是透明的,但在多线程环境中可能导致意外的行为。

JMM 通过引入内存屏障volatile 关键字来规范指令执行的顺序,从而避免指令重排序带来的问题。

声明一个变量为 volatile 可以确保这个变量的读写操作不会被重排序:

private volatile boolean flag = false;public void setFlag() {flag = true;
}public boolean checkFlag() {return flag;
}

JMM 通过这些规则和机制来实现多线程程序的正确性和一致性,确保程序在并发执行时能够以预期的方式运行,而不受硬件和编译器优化的影响,使得 Java 的多线程编程更具可预测性和可靠性。

4 JMM 对添加了 final 修饰符的类的字段有什么特殊保证 ?

final 字段比作一个已经封好的信封。假设你把一封信(即 final 字段)写好并封好(初始化完成),然后把它交给别人(其他线程)。一旦信封封好并且交给了别人,信封中的内容就不会再改变。其他人只要拿到这个信封,就可以确信里面的内容是完整和准确的,没有被修改过的可能性。

在 Java 内存模型中,给字段添加 final 修饰符会带来特别的保证,final 修饰的字段在对象构造完成后,会有一项确保该字段不会被改变的约束。

这样做的好处是,它保证了在构造器中对该字段的所有写入操作在其他线程看到对象时都是可见的,且这些写入操作不会被重排序,确保了对象的正确初始化。

有一个类 Person,它有一个 final 字段 name

public class Person {// Person 对象创建完成,name 的值就不能再改变private final String name;public Person(String name) {this.name = name;}public String getName() {return name;}
}

Java 的内存模型保证了在对象的构造完成后,所有线程都能看到 name 字段的正确值。这是因为构造完成后,final 字段的值写入将会被正确地发布到其他线程中,避免了由于内存重排序或缓存导致的读取不一致。

特别地,当一个对象被完全构造好并且对外可见时,所有 final 字段的值都已被正确地初始化。

这种保证也意味着,如果一个线程看到一个对象的 final 字段,那么它也能看到该对象的其他 final 字段及构造过程中的所有必要的初始化步骤。这就是 final 关键字在多线程环境中提供的内存可见性保证,使得 final 字段成为线程安全的。

在人生的旅途中,一定要学会自己拯救自己,这样才能在逆境中奋勇前行

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

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

相关文章

Spring扩展点系列-ApplicationContextAwareProcessor

文章目录 简介源码分析示例代码示例一&#xff1a;扩展点的执行顺序运行示例一 示例二&#xff1a;获取配置文件值配置文件application.properties内容定义工具类ConfigUtilcontroller测试调用运行示例二 示例三&#xff1a;实现ResourceLoaderAware读取文件ExtendResourceLoad…

论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey

Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染&#xff1a;一项综述 文章目录 大规模语言模型的基准数据污染&#xff1a;一项综述摘要1 引言 摘要 大规模语言模型&#xff08;LLMs&…

css——网格布局

名词解释 div{$}*9tab键&#xff0c;快捷生成 记首字母gtc 网格布局&#xff1a;display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; &#xff08;父元素&#xff09; <!DOCTYPE html> <html lang&q…

如何构建适合企业需求的即时通讯与音视频通话私有化平台?

在数字化转型的浪潮中&#xff0c;企业对于内部沟通的需求日益复杂化和多元化。传统的沟通方式已难以满足高效协作、信息安全及个性化定制的需求。因此&#xff0c;“即时通讯音视频通话”集成的私有化部署软件应运而生&#xff0c;成为企业优化内部沟通、提升工作效率的得力助…

PN IO设备ET 200SP支持R1模式

IA博途V18除了支持性能大幅提升的V3.0版本S7-1500 CPU&#xff08;不包含S7-1517/18 CPU&#xff09;外&#xff0c;还支持我们一直期待的R1模式的PROFINET IO设备ET200SP&#xff01;这样使S7-1500H 冗余系统的PN IO设备配置更加灵活。 1. PN 设备接口模式 以前的S7-1500R/…

【重学 MySQL】二十七、七种 join 连接

【重学 MySQL】二十七、七种 join 连接 union 的使用UNION 的基本用法示例UNION ALL 的用法 七种 join 连接代码实现语法格式小结 union 的使用 UNION 在 SQL 中用于合并两个或多个 SELECT 语句的结果集&#xff0c;并默认去除重复的行。如果希望包含重复行&#xff0c;可以使…

jmeter之setUP、tearDown线程组

setUp线程组&#xff1a; 用于在执行常规线程组之前执行一些必要的操作 ------会在普通线程组执行前被触发 应用场景举例&#xff1a; A、测试数据库操作功能时&#xff0c;用于执行打开数据库连接操作 B、测试用户购物功能时&#xff0c;用于执行用户的注册、登录等操作 tea…

DMDPC单副本集群安装

1. 环境描述 2. 部署步骤 2.1. 安装DM数据库软件启动DMAP [dmdbalei1 ~]$ DmAPService status DmAPService (pid 1269) is running.2.2. 初始化数据库实例 [dmdbalei1 data]$ dminit path/dmdba/data/sp1 instance_nameSP1 port_num5236 ap_port_num6000 dpc_modeSP initdb …

Java项目: 基于SpringBoot+mybatis+maven旅游管理系统(含源码+数据库+毕业论文)

一、项目简介 本项目是一套基于SpringBootmybatismaven旅游管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

Java 入门指南:Java 并发编程模式 —— 生产者-消费者模式

文章目录 生产者-消费者问题解决方案 生产者-消费者模式模式的核心问题基本原理生产者消费者 优点实现方式使用阻塞队列示例代码 使用 wait/notify 机制wait()notify()notifyAll()示例代码 使用 Exchanger示例代码 应用场景总结 生产者-消费者问题 生产者消费者问题是一个经典…

JS - 获取剪切板内容 Clipboard API

目录 1&#xff0c;需求最终效果 2&#xff0c;实现示例 3&#xff0c;注意点1&#xff0c;只支持安全上下文环境2&#xff0c;只能读取当前页面的剪切板3&#xff0c;权限获取问题4&#xff0c;获取内容的 MIME_TYPE 问题1&#xff0c;文本内容2&#xff0c;图片内容 5&#x…

3.C++入门(内联函数,c++11,auto,范围for,nullptr)

⭐本篇文章为C学习的第三篇&#xff1a;主要了解内联函数和部分c11新特性 ⭐本人c代码的Gitee仓库&#xff1a;c学习 橘子真甜/yzc的c学习 - 码云 - 开源中国 (gitee.com) 一. 内联函数 以inline修饰的函数称为内联函数&#xff0c;编译的时候c编译器会在内联函数的地方展开&a…

【GBase 8c V5_3.0.0 分布式数据库常用维护命令】

一、查看数据库状态/检查&#xff08;gbase用户&#xff09; 1.gha_ctl monitor 使用gha_ctl monitor查看节点运行情况(跟dcs的地址和端口) gha_ctl monitor -c gbase -l http://172.20.10.8:2379 -Hall |coordinator | datanode | gtm | server|dcs:必选字段。指定查看哪类集…

【有啥问啥】探索扫地机器人中的 SLAM 算法:原理、实现与未来展望

探索扫地机器人中的 SLAM 算法&#xff1a;原理、实现与未来展望 随着智能家居的普及&#xff0c;扫地机器人逐渐成为日常生活中的常见家电。其自主导航能力使得它能够在复杂的家庭环境中高效完成清洁任务&#xff0c;而这背后的核心技术之一就是 SLAM&#xff08;Simultaneou…

【文件包含】——日志文件注入

改变的确很难&#xff0c;但结果值得冒险 本文主要根据做题内容的总结&#xff0c;如有错误之处&#xff0c;还请各位师傅指正 一.伪协议的失效 当我们做到关于文件包含的题目时&#xff0c;常用思路其实就是使用伪协议&#xff08;php:filter,data,inpput等等&#xff09;执行…

shader 案例学习笔记之step函数

step函数 参数是float step(edge,x)&#xff1a;当x>edge时返回1&#xff0c;否则返回0 #ifdef GL_ES precision mediump float; #endifuniform vec2 u_resolution;void main(){vec2 st gl_FragCoord.xy/u_resolution.xy;float f step(0.5, st.x);gl_FragColor vec4(f…

算法知识点————数论【最大公约数】【快速幂】【分解质因数】

结论1&#xff1a;两个互质的整数mn不能凑出的最大整数是(n-1)(m-1) -1 结论2:一个数的因数可以拆成n个质因数的乘积。 黄金分割&#xff1a;0.61803399 在数论中&#xff0c;如果两个或两个以上的整数的最大公约数是 1 &#xff0c;则称它们为互质。 最大公约数: 两数乘积最…

C语言:结构体

在前面我们已经介绍了整形&#xff0c;浮点型&#xff0c;字符型&#xff0c;还介绍了数组&#xff0c;字符串。但是在实际问题中只有这些数据类型是不够的&#xff0c;有时候我们需要其中的几种一起来修饰某个变量&#xff0c;例如一个学生的信息就需要学号&#xff08;字符串…

基础 Web 开发

1. 构建项目&#xff1a; 2.添加依赖 <dependencies> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupI…

[ RK3566-Android11 ] 关于 RK628F 驱动移植以及调试说明

问题描述 我这个项目的SDK比较老&#xff0c;移植RK628F最新驱动的调试过程&#xff0c;踩了很多坑&#xff0c;希望大家别踩坑。 解决方案&#xff1a; 首先在FTP上下载最新的RK628的驱动 rk628-for-all-v27-240730 版本。 下载完后 不要直接替换&#xff0c;不要直接替换&a…