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

news2024/11/18 23:51:29

在这里插入图片描述

文章目录

    • 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.coloradmin.cn/o/2132854.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Dubbo精要

1、为什么需要 Dubbo&#xff1f; 分布式系统中的服务调用和协调问题&#xff1a;在分布式系统中&#xff0c;服务之间的相互依赖会导致复杂的通信和协调问题。Dubbo提供了高效的服务调用和自动注册、发现等功能&#xff0c;使得构建分布式应用程序更加容易。服务治理和服务调…

6 递归——509. 斐波那契数 ★

6 递归 509. 斐波那契数 斐波那契数列从0和1开始,后面的每一项数字都是前面两项数字的和。F(0) = 0,F(1) = 1,当n > 1时,F(n) = F(n − 1) + F(n − 2)。给定n,请计算 F(n)。 示例 1: 输入:n = 2 输出:1 解释:F(2) = F(1) + F(0) = 1 + 0 = 1 示例 2: 输入:n …

[000-01-008].第05节:OpenFeign特性-重试机制

我的后端学习大纲 SpringCloud学习大纲 1.1.重试机制的默认值&#xff1a; 1.重试机制默认是关闭的&#xff0c;给了默认值 1.2.测试重试机制的默认值&#xff1a; 1.3.开启Retryer功能&#xff1a; 1.修改配置文件YML的配置&#xff1a; 2.新增配置类&#xff1a; packa…

CentOs 入门必备基础知识详细讲解

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; CentOS&#xff08;Community ENTerprise Operating System&#xff09;是一个基于 Red Hat Enterprise Linux (RHEL) 源代码的开源操作系统&#xff0c;主要用于服务器和企业环境。下面是一个详细的入门知识…

JDBC数据库连接技术

JDBC数据库连接技术 基础篇 一、引言 1.1 数据的存储 我们在开发Java程序时&#xff0c;数据都是存储在内存中&#xff0c;属于临时存储&#xff0c;当程序停止或重启时&#xff0c;内存中的数据就丢失了&#xff01;我们为了解决数据的长期存储问题&#xff0c;有如下解决方…

【Prompt Enhancer】如何优化prompt的内容

背景 在使用LLM的时候&#xff0c;提示词的好坏对模型的输出质量影响很大&#xff0c;提示词又是一个复杂工程&#xff0c;要写出优秀的提示词&#xff0c;需要丰富的经验。正因如此&#xff0c;各类Agent平台都会有自己的提示词增强功能&#xff0c;帮助用户编写提示词。 最…

Linux驱动.之platform平台总线驱动框架(二),正点原子

第五十四章 platform设备驱动实验 我们在前面几章编写的设备驱动都非常的简单&#xff0c;都是对IO进行最简单的读写操作。像I2C、SPI、LCD等这些复杂外设的驱动就不能这么去写了&#xff0c;Linux系统要考虑到驱动的可重用性&#xff0c;因此提出了驱动的分离与分层这样的软件…

数据结构与算法-17高级数据结构_图论(迪杰斯特拉算法)

迪杰斯特拉算法 1 是什么&#xff1f; 迪杰斯特拉算法&#xff08;Dijkstra’s Algorithm&#xff09;&#xff0c;又称狄克斯特拉算法&#xff0c;是由荷兰计算机科学家埃德加狄克斯特拉&#xff08;Edsger Dijkstra&#xff09;于1959年提出的一种用于解决有权图中最短路径…

GPT-4与ChatGPT:人工智能对话的新时代【含国内可用gpt】

随着人工智能&#xff08;AI&#xff09;技术的不断突破&#xff0c;人与机器的交互方式正发生深刻的变革。在这股技术浪潮中&#xff0c;GPT-4和基于它的ChatGPT成为了令人瞩目的焦点&#xff0c;推动了对话式AI的快速发展。通过这些技术&#xff0c;我们不仅看到了AI在语言理…

【MySQL】MySQL和Workbench版本兼容问题

1、安装MySQL WorkBench 最新版本下载&#xff1a;https://dev.mysql.com/downloads/workbench/ 历史版本下载&#xff1a;https://downloads.mysql.com/archives/workbench/ 2、问题描述 本人在Windows下安装了一个旧版本的MySQL&#xff08;5.1&#xff09;&#xff0c;同…

全球NAND原厂闪存市场格局变化

根据市场研究机构TrendForce的最新跟踪报告&#xff0c;三星&#xff08;Samsung&#xff09;和SK海力士&#xff08;SK hynix-Solidigm&#xff09;在过去的一个季度中扩大了他们在NAND闪存市场的份额&#xff0c;这主要得益于抢占了铠侠&#xff08;Kioxia&#xff09;与西部…

Threejs之加载3D模型(下)

本文目录 前言一、代码示例1.1 FBXLoader1.1.1 代码1.1.2 效果1.1.3 动画1.1.3.1 动画效果 1.2 ColladaLoader1.2.1 代码1.2.2 效果 前言 本篇博客基于Threejs之加载3D模型&#xff08;上&#xff09;追加常用模型加载示例。 一、代码示例 1.1 FBXLoader 构造函数 FBXLoader(…

【C++指南】作用域限定符 :: 使用详解

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C指南》 期待您的关注 目录 引言 1. 访问全局变量 2. 命名空间中的成员访问 3. 类的静态成员访问 4. 嵌套命名空间/类中的…

钾盐矿开采与加工过程中的机电设备选型及管理指南

创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 在钾盐矿的开采和加工过程中&#xff0c;需要使用多种机电设备以确保生产的顺利进行。这些设备主要用于矿石开采、破碎、运输、选矿以及矿物产品的深加工等过程。以下是钾盐矿常用的一些机…

vulnhub靶机:Holynix: v1

下载 下载地址&#xff1a;https://www.vulnhub.com/entry/holynix-v1,20/ 打开虚拟机 选择下载解压之后的文件打开 新添加一张 NAT 网卡&#xff0c;mac 地址修改如下 00:0c:29:bc:05:de 给原来的桥接网卡&#xff0c;随机生成一个 mac 地址 然后重启虚拟机 信息收集 主…

C++多态讲解

多态 多态的概念 通俗来说&#xff0c;就是多种形态。多态分为编译时多态(静态多态)和运行时多态(动态多态)这里重点讲运行时多态。 运行时多态 运行时多态&#xff0c;具体点就是去完成某个行为(函数)&#xff0c;可以传不同的对象就会完成不同的行为&#xff0c;就达到多种形…

在VMware上怎么安装Windows11?看这个教程就足够了

前言 Windows11与Windows10或以下版本有个最大的不同&#xff0c;就是有配置要求。 它就是TPM 2.0。 TPM的全称是Trusted Platform Module&#xff0c;中文名称为&#xff1a;可信赖平台模块。 其中TPM 2.0与上一代的版本&#xff08;TPM 1.2&#xff09;有什么区别&#xf…

使用视图方式操作MySQL数据表

7.1  认识视图 7.1.1  视图的含义 视图是一种常用的数据库对象&#xff0c;可以把它看成从一个或几个源表导出的虚表或存储在数据库中的查询&#xff0c;对视图所引用的源表来说&#xff0c;视图的作用类似于筛选。 视图一经定义后&#xff0c;就可以像源表一样被查询、修…

如何看待 IBM 中国研发部裁员

一、引言 在全球信息技术飞速发展的时代&#xff0c;跨国科技企业一直扮演着重要的角色。IBM&#xff0c;作为全球知名的信息技术和业务解决方案公司&#xff0c;在中国市场也有着长期的发展历程。然而&#xff0c;近日 IBM 中国宣布撤出在华两大研发中心&#xff0c;进行大规…

Python画笔案例-045 绘制渐变圆盘

1、绘制 渐变圆盘 通过 python 的turtle 库绘制 渐变圆盘&#xff0c;如下图&#xff1a; 2、实现代码 绘制 渐变圆盘&#xff0c;以下为实现代码&#xff1a; """本程序需要coloradd模块支持,安装方法pip install coloradd """ import turtle …