当前位置: 首页 > news >正文

高性能锁机制 CAS:Java 并发编程中的深度剖析

引言

在并发编程领域,i++操作的非线程安全性是开发者们熟知的问题。这一现象根源在于i++并非原子操作,其内部执行过程包含读取、修改和写入三个步骤,在多线程环境下极易因线程切换导致数据竞争与不一致,这与我们此前探讨的多线程常见问题紧密相关。

为保障操作的原子性,加锁机制成为常见解决方案。在 Java 技术栈中,synchronized关键字与 CAS(Compare And Swap,比较与交换)机制是实现线程同步的两大核心手段。但二者在设计理念与执行逻辑上存在显著差异,分别对应悲观锁与乐观锁两种截然不同的并发控制策略。

悲观锁:以synchronized为代表的保守策略

synchronized作为悲观锁的典型代表,自 JDK 早期版本便已存在。尽管随着 JDK 的迭代优化,其性能表现大幅提升,从重量级锁逐步演变为轻量级锁与偏向锁,但本质上仍属于悲观锁范畴。

悲观锁的设计哲学在于对冲突的高度警惕,它默认每次访问共享资源时都可能发生竞争,因此强制要求线程在进入临界区前必须获取锁。以i++操作为例,当一个线程通过synchronized锁定目标变量后,其他线程若试图访问该变量,将立即被阻塞并进入等待队列,直至持有锁的线程执行完毕并释放锁资源。这一过程可类比为日常生活场景:当一人进入卫生间后立即反锁房门(获取锁),在其使用完毕并开门(释放锁)前,后续使用者只能在外等候(线程阻塞),即便需求迫切也无法强行进入。这种策略虽能确保数据安全,但频繁的锁获取与释放操作,以及线程阻塞带来的上下文切换开销,在高并发场景下可能成为性能瓶颈。

乐观锁:基于 CAS 的积极尝试

与悲观锁形成鲜明对比,CAS 机制作为乐观锁的核心实现,展现出截然不同的并发控制思路。乐观锁假定在大多数情况下,线程对共享资源的访问不会产生冲突,因此线程执行时无需预先加锁,而是直接尝试完成操作。

具体到i++场景,线程首先读取变量的当前值作为预期值,随后在修改并写入新值前,通过 CAS 操作比较内存中的实际值是否与预期值一致。若一致,则原子性地更新变量;若不一致,说明在此期间有其他线程已修改该变量,当前线程将重新读取最新值并再次尝试,直至操作成功。这一过程类似于多人协作填写共享表格,每个人在提交修改前会检查内容是否被他人改动,若未变动则提交,否则重新获取最新版本进行修改。由于乐观锁避免了线程阻塞,显著减少了上下文切换开销,尤其适用于读多写少的场景。此外,因其无需显式加锁与解锁,从原理上杜绝了死锁产生的可能性。

接下来我们来有条理且全面的理解一下CAS。

一、CAS 核心原理

CAS 的核心思想基于比较 - 验证 - 更新的原子性操作流程,其核心目标是在多线程环境下实现共享变量的原子更新。CAS 操作涉及三个关键操作数:

  1. V(Var):待更新的共享变量
  1. E(Expected):预期值,即操作前读取到的变量值
  1. N(New):新值,用于替换 V 的目标值

当且仅当内存中的变量 V 当前值等于预期值 E 时,CAS 操作才会将 V 原子性地更新为新值 N;若 V 的值已被其他线程修改(即 V != E),则更新失败,当前线程可选择重试或放弃操作。这种机制通过硬件级别的原子指令实现,避免了传统锁机制带来的线程阻塞和上下文切换开销,显著提升并发性能。

二、CAS在Java 中的实现:通过Unsafe 类与底层硬件协同实现

在 Java 中,CAS 操作的实现依赖于sun.misc.Unsafe类。该类提供了compareAndSwapObject、compareAndSwapInt、compareAndSwapLong等方法,用于对不同类型的共享变量执行 CAS 操作。值得注意的是,Unsafe类中的 CAS 方法均为native方法,其底层实现依赖于操作系统和 CPU 架构,通过 JNI(Java Native Interface)调用 C/C++ 代码实现。

以AtomicInteger为例,其核心源码展示了 CAS 的具体应用:

public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// 获取Unsafe类实例private static final Unsafe unsafe = Unsafe.getUnsafe();// 存储value字段的内存偏移量private static final long valueOffset;static {try {// 初始化时获取value字段的内存偏移量valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) {throw new Error(ex);}}// 使用volatile保证可见性private volatile int value;// 通过CAS机制更新valuepublic final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}
}

上述代码中,unsafe.compareAndSwapInt方法通过内存偏移量valueOffset直接定位变量在内存中的地址,并执行原子更新操作。这一过程依赖于底层 CPU 提供的原子指令,如 x86 架构下的CMPXCHG指令,确保同一时刻只有一个线程能够修改目标内存地址。

注:

  • 偏移量:在 CAS(Compare and Swap)操作中,偏移量指的是对象属性在内存中的相对位置。Java 通过 Unsafe 类提供的objectFieldOffset方法获取目标属性相对于对象起始地址的偏移量,这个偏移量是实现原子更新的关键。例如,在AtomicInteger中对value字段进行 CAS 更新时,首先需要获取value字段的偏移量,后续的比较和替换操作都是基于这个偏移量直接在内存层面进行,绕过了传统锁机制带来的性能损耗,从而实现高效的并发数据修改 。

三、CAS 在 Java 中的应用:通过atomic类调用Unsafe类实现原子操作

3.1 原子类的底层实现原理

在java.util.concurrent.atomic包中,AtomicInteger、AtomicLong、AtomicReference等原子类均以 CAS 机制作为核心实现,源码调用了Unsafe类码。这些原子类采用无锁自旋重试策略,通过循环尝试更新共享变量,直到操作成功。这种设计巧妙地避免了传统锁机制导致的线程阻塞问题。在高并发场景下,原子类通过减少锁竞争带来的开销,显著提升了数据更新的效率。

AtomicInteger 核心源码部分

// 获取Unsafe实例
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;static {try {// 获取“value”字段在AtomicInteger类中的内存偏移量valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) {throw new Error(ex);}
}// 确保“value”字段的可见性
private volatile int value;/*** 如果当前值等于预期值,则原子地将值设置为newValue* 使用Unsafe#compareAndSwapInt方法进行CAS操作*/
public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}/*** 原子地将当前值加delta并返回旧值*/
public final int getAndAdd(int delta) {return unsafe.getAndAddInt(this, valueOffset, delta);
}/*** 原子地将当前值加1并返回加之前的值(旧值)* 使用Unsafe#getAndAddInt方法进行CAS操作*/
public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);
}/*** 原子地将当前值减1并返回减之前的值(旧值)*/
public final int getAndDecrement() {return unsafe.getAndAddInt(this, valueOffset, -1);
}

Unsafe#getAndAddInt 源码部分

/*** 原子地获取并递增指定对象的整数值* @param o 目标对象* @offset 内存偏移量* @delta 增量值* @return 修改前的旧值*/
public final int getAndAddInt(Object o, long offset, int delta) {int v;do {// 以 volatile 语义获取当前值v = getIntVolatile(o, offset);} while (!compareAndSwapInt(o, offset, v, v + delta)); // CAS 更新直到成功return v;
}

请注意,上述代码中直接使用Unsafe.getUnsafe()在正常 Java 应用中可能会抛出安全异常,因为Unsafe类主要用于底层、高风险的操作,一般在 Java 核心库内部使用 。

3.2 非阻塞数据结构的实现

CAS 机制是构建非阻塞数据结构的基石,典型代表包括ConcurrentLinkedQueue和ConcurrentSkipListMap。在这些数据结构中,节点的插入、删除与修改操作均依赖 CAS 指令完成。通过直接比较并更新内存中的节点引用,在无需加锁的前提下,确保数据操作的原子性与线程安全性,实现高效的并发访问控制。

四、CAS 的问题与解决方案

4.1 ABA 问题:数据一致性的潜在威胁

问题描述:当线程 A 读取到变量值为 A,在准备更新为 B 之前,其他线程将变量值从 A 修改为 B 再改回 A。此时线程 A 执行 CAS 操作时,由于当前值与预期值均为 A,操作成功,但实际数据已被修改,可能导致业务逻辑错误。

解决方案

  1. 版本号机制:为变量添加版本号,每次修改时版本号递增。CAS 操作时同时比较版本号和变量值,确保数据的一致性。
  1. 时间戳机制:使用时间戳记录变量的修改时间,类似版本号机制,通过对比时间戳判断数据是否被篡改。

4.2 自旋开销:CPU 资源的过度消耗

问题描述:CAS 操作通常采用自旋重试策略,若长时间更新失败,将导致 CPU 资源被无效占用,影响系统整体性能。

解决方案

  1. 引入pause指令:现代 CPU 支持pause指令,在自旋失败时让 CPU 短暂休眠,降低内存访问频率,减少流水线重排带来的开销。
  1. 自适应自旋:根据历史操作成功率动态调整自旋次数,避免无限循环。

4.3 单变量限制:复杂场景的局限性

问题描述:CAS 仅支持对单个共享变量的原子操作,无法直接处理多个变量的组合更新场景。

解决方案

  1. 封装对象:使用AtomicReference将多个变量封装为一个对象,通过操作对象实现原子更新。
  1. 分段锁机制:将数据划分为多个段,每个段独立使用 CAS 操作,减少锁竞争范围。

五、博主总结

  • CAS(属于锁机制里面的内容)
    • CAS基本(是什么?机制是什么?)
      • CAS 的全称是 Compare And Swap(比较与交换),核心是实现原子性的更新。
      • CAS 的思想很简单,即只有当内存中的值等于预期值时,才更新为新值,否则不更新。整个过程是原子的,不会被其他线程打断。
      • CAS 涉及到三个操作数:
        • V:要更新的变量值(Var)
        • E:预期值(Expected)
        • N:拟写入的新值(New)
      • 当且仅当 V 的值等于 E 时,CAS 通过原子方式用新值 N 来更新 V 的值。如果不等,说明已经有其它线程更新了 V,则当前线程放弃更新。
      • 注意:当多个线程同时使用 CAS 操作一个变量时,只有一个会成功更新,其余均会失败,但失败的线程并不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。
    • java中CAS是如何实现的?(Unsafe类)
      • sun.misc包下的Unsafe类,这个类是一个提供低级别、不安全操作的类。由于其强大的功能和潜在的危险性,它通常用于 JVM 内部或一些需要极高性能和底层访问的库中,而不推荐普通开发者在应用程序中使用。Unsafe类提供了compareAndSwapObject、compareAndSwapInt、compareAndSwapLong方法来实现的对Object、int、long类型的 CAS 操作。

      • Unsafe类中的 CAS 方法是native方法。native关键字表明这些方法是用本地代码(通常是 C 或 C++)实现的,而不是用 Java 实现的。这些方法直接调用底层的硬件指令来实现原子操作。也就是说,Java 语言并没有直接用 Java 实现 CAS。
      • 更准确点来说,Java 中 CAS 是 C++ 内联汇编的形式实现的,通过 JNI(Java Native Interface) 调用。因此,CAS 的具体实现与操作系统以及 CPU 密切相关。
      • 底层实现。

    • Java 如何使用Unsafe类的方法来实现原子操作?(通过Atomic类调用)
      • Atomic类依赖于 CAS乐观锁来保证其方法的原子性,而不需要使用传统的锁机制(如 synchronized 块或 ReentrantLock)。
      • AtomicInteger是 Java 的原子类之一,主要用于对 int 类型的变量进行原子操作,它利用Unsafe类提供的低级别原子操作方法实现无锁的线程安全性。
      • 附上核心源码分析助于理解

    • CAS算法存在哪些问题?
      • ABA问题
        • 是什么?ABA问题是在使用CAS时可能出现的一种并发问题。在多线程环境下,如果一个变量的值先被线程A修改为B,然后又被线程B修改回A,那么在使用CAS进行比较和交换操作时,尽管变量的当前值与预期值相同(都是A),但实际上这个变量的值已经被修改过,这就是ABA问题。
        • 怎么解决?在变量前面追加上版本号或者时间戳。
      • 循环时间长开销大
        • 是什么?CAS 经常会用到自旋操作来进行重试,也就是不成功就一直循环执行直到成功。如果长时间不成功,会给 CPU 带来非常大的执行开销。
        • 怎么解决?解决思路是让 JVM 支持处理器提供的pause 指令。pause 指令能让自旋失败时 cpu 睡眠一小段时间再继续自旋,从而使得读操作的频率降低很多,为解决内存顺序冲突而导致的 CPU 流水线重排的代价也会小很多。
      • 只能保证一个共享变量的原子操作
        • 是什么?CAS 操作仅能对单个共享变量有效。当需要操作多个共享变量时,CAS 就显得无能为力。
        • 怎么解决?Java 提供了AtomicReference类,通过将多个变量封装在一个对象中,我们可以使用AtomicReference(原子性)来执行 CAS 操作。还可以利用加锁来保证但是性能差。
    • 有的同学会问为什么在解决ABA问题时,CAS都加上版本号或时间戳了,那为什么不直接只使用一个版本号法去实现线程安全呢?
      • 原因在于 CAS 的核心目标不仅仅是线程安全,而是 原子性更新:机制是先进行一致性校验,后进行通过java的Atomic类调用Unsafe类进行原子性更新操作。比较并交换,是原子性更新的基础。
      • 什么是原子性更新?
        • 不可分割性:操作要么全部完成,要么全部不完成。
        • 中间状态不可见:其他线程无法看到操作的中间状态。
        • 线程安全:无需额外同步机制即可保证正确性。
      • 那他是怎么保证原子性更新的呢?
        • 自旋重试​:如果CAS失败(值被其他线程修改),则重试,直到成功。
        • Unsafe 类通过 JNI (Java Native Interface,Java 本地接口)调用本地方法,直接操作内存。底层调用(如x86的CMPXCHG),CPU会加锁确保同一时间只有一个线程能修改该内存地址。
        • volatile保证可见性​:确保多线程能立即看到最新值。
    • Unsafe类和Atomic类详解
      • Java 魔法类 Unsafe 详解(关于实现CAS)
      • Atomic 原子类总结(关于乐观锁针对的是单个共享变量、以及实现CAS)
    • 偏移量offset,使用偏移量直接操作内存,实现原子性更新。
      • CAS 会先读取字段的实际值(通过偏移量 valueOffset 定位内存地址)。

相关文章:

高性能锁机制 CAS:Java 并发编程中的深度剖析

引言 在并发编程领域,i操作的非线程安全性是开发者们熟知的问题。这一现象根源在于i并非原子操作,其内部执行过程包含读取、修改和写入三个步骤,在多线程环境下极易因线程切换导致数据竞争与不一致,这与我们此前探讨的多线程常见问…...

leetcode 每日一题 1931. 用三种不同颜色为网格涂色

题目 1931. 用三种不同颜色为网格涂色 思路 先获取列表,上下左右的所有情况。解决一维的问题 然后所有一维的问题暴力循环。已知一个一维的解,可以对应其他一维解的列表(用于记忆化搜索) 然后使用递归,进行累加 代…...

解决Windows磁盘管理中因夹卷导致的无法分区问题

解决Windows磁盘管理中因夹卷导致的无法分区问题 在现代计算机管理中,磁盘分区是一个常见且重要的操作。无论是为了优化存储空间,还是为了实现多系统安装,合理的磁盘分区都是必不可少的。然而,许多用户在使用Windows磁盘管理工具…...

龙虎榜——20250519

上证指数缩量收十字星,个股涨多跌少,这周反弹的概率比较大。 深证指数缩量调整,临近反弹,个股表现更好。 2025年5月19日龙虎榜行业方向分析 化工(新能源材料国产替代) • 代表个股:红宝丽、…...

Python在自动驾驶数据清洗中的应用

Python在自动驾驶数据清洗中的应用 在自动驾驶领域,数据是算法的燃料。高质量的数据意味着更精准的模型,更稳定的驾驶体验。然而,原始数据通常充满噪声、缺失值、不一致格式,甚至有异常点,这些都会严重影响自动驾驶系统的可靠性。因此,数据清洗是一道绕不开的关卡。 一…...

腾讯云Mysql实现远程链接

1.SQL语句:CREATE USER remote_user% IDENTIFIED BY YourPassword; GRANT ALL PRIVILEGES ON *.* TO remote_user%; FLUSH PRIVILEGES; 2.设置入站规则 3.设置安全组 4.效果...

大模型(2)——提示工程(Prompt Engineering)

文章目录 一、提示工程的核心概念为什么需要提示工程? 二、提示设计的基本原则三、实用提示工程技巧1. 角色设定法2. 示例引导法(Few-Shot Learning)3. 分阶段提问4. 负面约束5. 温度(Temperature)控制 四、不同任务类…...

深入Java G1 GC调优:如何解决高延迟与吞吐量瓶颈

引言 Java的垃圾回收(GC)机制是JVM性能的核心,但即使是最先进的G1(Garbage-First)收集器,在复杂场景下仍可能引发长时间停顿(Stop-The-World, STW)​或吞吐量骤降。许多开发者虽然熟…...

DAPO:用于指令微调的直接偏好优化解读

一、背景与动机:从RLHF到DPO,再到DAPO 大型语言模型(LLM)经过海量无监督预训练后,往往需要对齐人类偏好或遵循指令的微调,使模型的回答更符合人类期望。这一过程通常通过人类反馈强化学习(RLHF)来实现。例如OpenAI的ChatGPT就使用了RLHF:先让人工标注对模型输出进行偏…...

vue2、vue3项目打包生成txt文件-自动记录打包日期:git版本、当前分支、提交人姓名、提交日期、提交描述等信息 和 前端项目的版本号json文件

vue2 打包生成text文件 和 前端项目的版本号json文件 项目打包生成txt文件-自动记录git版本、当前分支、提交人姓名、提交日期、提交描述等信息生成版本号json文件-自动记录当前版本号、打包时间等信息新建branch-version-webpack-plugin.js文件 // 同步子进程 const execSyn…...

iOS解码实现

import Foundation import VideoToolboxclass KFVideoDecoderInputPacket {var sampleBuffer: CMSampleBuffer? }class KFVideoDecoder {// MARK: - 常量private let kDecoderRetrySessionMaxCount 5private let kDecoderDecodeFrameFailedMaxCount 20// MARK: - 回调var pi…...

Windows中PDF TXT Excel Word PPT等Office文件在预览窗格无法预览的终级解决方法大全

Windows中PDF TXT Excel Word PPT等Office文件在预览窗格无法预览的终级解决方法大全 参考链接: https://zhuanlan.zhihu.com/p/454259765...

在Excel中使用函数公式时,常见错误对应不同的典型问题

在Excel中使用函数公式时,常见错误对应不同的典型问题 1. #DIV/0!(除以零错误)2. #N/A(值不可用)3. #NAME?(名称错误)4. #NULL!(空交集错误)5. #NUM!(数值错…...

Excel

1.快捷键 CtrlE 快速填充 CtrlQ 快速分析 CtrlEnter 原位填充 Tab 横向移动到下一个单元格 Enter 移动到下一行起始位置对应单元格 Shift 返回上一个单元格 0空格分数 显示分数 1.if if(condition,true,false)if(A1>10,"true","fa…...

Rust 学习笔记:错误处理

Rust 学习笔记:错误处理 Rust 学习笔记:错误处理不可恢复的错误带有结果的可恢复错误匹配不同的错误出现错误时 panic 的快捷方式:unwrap 和 expect传播错误传播错误的快捷方式:? 操作符哪里可以使用 ? 操作符 panic or not pan…...

【Linux】系统指令与开发全栈(vim、ssh、gcc)

【Linux】系统指令与开发全栈(vim、ssh、gcc) 一、Linux 系统指令大全 1、文件与目录管理 基础操作 指令参数说明典型用例注意事项cd~ 家目录,- 返回上级,.. 上级目录cd ~/Documents 进入文档目录无目录权限时会报错ls-l 详情&am…...

用 CodeBuddy 搭建「MiniGoal 小目标打卡器」:一次流畅的 UniApp 开发体验

我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 在日常生活中,我们总是希望能够坚持一些小习惯,比如每天锻炼十分钟、读一页书、早睡十分…...

前端(vue)学习笔记(CLASS 6):路由进阶

1、路由的封装抽离 将之前写在main.js文件中的路由配置与规则抽离出来,放置在router/index.js文件中,再将其导入回main.js文件中,即可实现路由的封装抽离 例如 //index.js import { createMemoryHistory, createRouter } from vue-routerim…...

ubuntu 安装 Redis新版Redis 7.x

以下是在Ubuntu系统中安装Redis的详细指南, 一、官方APT源安装 sudo apt install redis-server -y 默认安装最新APT源版本(Ubuntu 22.04通常为Redis 6.x) 服务自动启动,配置文件路径:/etc/redis/redis.conf验证安装 …...

Httphelper: Http请求webapi小记

文章目录 1、HttpHelper.cs Framework4.812、HttpHelper.cs NET83、JsonHelper.cs Framework4.814、JsonHelper.cs NET85、uniapp request.js 访问WEBAPI 每次查找、测试都比较费事,记录一下把 1、HttpHelper.cs Framework4.81 using System; using System.IO; usi…...

【Linux】进程控制(进程创建、进程终止、进程等待、进程替换)

目录 一、进程创建 1、fork函数 2、页表权限 二、进程终止 1、main函数返回值(退出码) 2、常见错误码及其对应的错误描述: 将错误退出码转化为错误描述的方法: 3、进程退出的三种场景 4、由上我们可以知道: 5…...

java+selenium专题->启动浏览器下篇

1.简介 上一篇文章,我们已经在搭建的java项目环境中实践了,今天就在基于maven项目的环境中演示一下。 2.eclipse中新建maven项目 1.依次点击eclipse的file - new - other ,如下图所示: 2.在搜索框输入关键字“maven”&#xff…...

sqlserver 循环删除1000行

在SQL Server中,如果你想循环删除1000行数据,有几种方法可以实现,但值得注意的是,频繁使用循环删除操作可能会对数据库性能造成影响,尤其是在处理大量数据时。下面介绍几种方法,并讨论它们的优缺点。 方法…...

亚信电子与联发科技携手打造AIoT新未来

[台湾新竹讯, 2025年5月19日] 智能物联网(AIoT)融合人工智能与物联网技术,通过边缘AI的实时数据分析及设备智能联网能力,加速智能物联网创新应用的蓬勃发展。为满足AIoT产业对多网络端口的应用需求,全球半导体公司【联…...

【成品设计】基于STM32的人体健康监测系统

《基于STM32的人体健康监测系统》 Ps:有4个版本。 V1硬件设计: 主控:STM32F103C8T6:作为系统主控芯片。 血氧心率传感器:用于采集当前心率、血氧值。 温湿度传感器:用于采集当前环境温湿度。 有源低电平触发蜂鸣器&…...

【MySQL进阶】了解linux操作系统下mysql的配置文件和常用选项

前言 🌟🌟本期讲解关于linux下mysql配置选项的详细介绍~~~ 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 🔥 你的点赞就是小编不断更新的最大动力 🎆那么…...

LeetCode 219.存在重复元素 II

目录 题目: 题目描述: 题目链接: 思路: 核心思路: 思路详解: 代码: C代码: Java代码: 题目: 题目描述: 题目链接: 219. 存…...

解释:神经网络

在过去的10年里,表现最好的artificial-intelligence系统——比如智能手机上的语音识别器或谷歌最新的自动翻译——都是由一种叫做“深度学习”的技术产生的 深度学习实际上是一种被称为神经网络的人工智能方法的新名称,这种方法已经流行了70多年。1944年…...

Java 泛型详解

在 Java 的类型系统中,泛型(Generics) 是一个非常重要的特性。它让我们能够编写更通用、更安全的代码,尤其是在处理集合类(如 List、Map 等)时,泛型的使用可以大大减少类型转换的麻烦&#xff0…...

React集成百度【JSAPI Three】教程(001):快速入门

文章目录 1、快速入门1.1 创建react项目1.2 安装与配置1.3 静态资源配置1.4 配置百度地图AK1.5 第一个DEMO1、快速入门 JSAPI Three版本是一套基于Three.js的三维数字孪生版本地图服务引擎,一套引擎即可支持2D、2.5D、3D全能力的地理投影与数据源加载,帮助开发者轻松搞定平面…...

WPF中资源(Resource)与嵌入的资源(Embedded Resource)的区别及使用场景详解

🌟 开发WPF项目时图片、SVG、配置文件等到底该设置为哪种资源?如何正确读取、跨程序集访问?一篇文章全解答。 在使用 WPF 进行项目开发时,很多开发者在设置文件“生成操作(Build Action)”时,常常会在“资源(Resource)”和“嵌入的资源(Embedded Resource)”之间感…...

如何在 Windows 11 或 10 上安装 Fliqlo 时钟屏保

了解如何在 Windows 11 或 10 上安装 Fliqlo,为您的 PC 或笔记本电脑屏幕添加一个翻转时钟屏保以显示时间。 Fliqlo 是一款适用于 Windows 和 macOS 平台的免费时钟屏保。它也适用于移动设备,但仅限于 iPhone 和 iPad。Fliqlo 的主要功能是在用户不活动时在 PC 或笔记本电脑…...

【STM32】ST-Link V2.1制作

一、下载烧写工具及程序 下载器制作(ST-Link V2.1) 链接: 提取码:6666https://pan.baidu.com/s/1n0RYNDEw5mBT_CsTFoqrIg?pwd6666 二、安装STM32 CubeProgrammer 双击安装包,点击Next 继续点击Next 选择安装路径,再…...

day30python打卡

知识点回顾: 导入官方库的三种手段导入自定义库/模块的方式导入库/模块的核心逻辑:找到根目录(python解释器的目录和终端的目录不一致) 作业:自己新建几个不同路径文件尝试下如何导入 一、导入官方库 我们复盘下学习py…...

AI大语言模型评测体系演进与未来展望

随着人工智能技术的飞速发展,大语言模型(LLMs)已成为自然语言处理领域的核心研究方向。2025年最新行业报告显示,当前主流模型的评测体系已从单一任务评估转向多维度、全链路的能力剖析。例如,《全球首个大语言模型意识水平”识商”白盒DIKWP测评报告》通过数据、信息、知识…...

用Python将 PDF 中的表格提取为 Excel/CSV

*用Python将 PDF 中的表格提取为 Excel/CSV,*支持文本型 PDF 和 扫描件/图片型 PDF(需 OCR 识别)。程序包含以下功能: 1.自动检测 PDF 类型(文本 or 扫描件) 2.提取表格数据并保存为 Excel/CSV 3.处理多页…...

【工具】ncdu工具安装与使用指南:高效管理Linux磁盘空间

磁盘空间管理是Linux系统维护中的关键任务。当系统提示"磁盘空间不足"时,快速找出占用大量空间的文件和目录变得尤为重要。虽然传统的du命令可以完成这项工作,但其输出往往难以阅读和分析。本文介绍的ncdu(NCurses Disk Usage&…...

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Progress Steps (步骤条)

📅 我们继续 50 个小项目挑战!—— Progress Steps 组件 仓库地址:https://github.com/SunACong/50-vue-projects 项目预览地址:https://50-vue-projects.vercel.app/ ✨ 组件目标 展示一个多步骤的进度条,指示当前所…...

数据分析—Excel数据清洗函数

在做数据分析的过程中,我们从数据库或者网页中获取的外部数据,通常是无法直接使用进行数据分析的。数据经常会有尾随的空格、奇奇怪怪的前缀和非打印字符等等问题,那么我们就需要先对数据进行清洗。下面介绍一些在数据清洗过程中常用的Excel函…...

CEF源码历史版本编译避坑指南

cef编译,网上查到的相关资料大多是官网上自动化编译的翻版,可能较新的版本按照那个步骤编译是没问题的。但是,对于历史版本的编译就会遇到各种坑。步骤大同小异,所以不再赘述,重点记录下针对历史版本编译要注意的点&am…...

看之前熟悉双亲委派加载机制,看之后了解双亲委派加载机制

今天面试被拷打双亲委派加载机制了,麻了。 首先要介绍双亲委派加载机制,就需要先搞明白啥是Java的类加载机制。 一.介绍 Java虚拟机(JVM)作为Java语言的核心运行环境,承担着将Java字节码转换为机器码并执行的重任。…...

std::ranges::views::stride 和 std::ranges::stride_view

std::ranges::views::stride 是 C23 中引入的一个范围适配器,用于创建一个视图,该视图只包含原始范围中每隔 N 个元素的元素(即步长为 N 的元素)。 基本概念 std::ranges::stride_view 是一个范围适配器,接受一个输…...

IBM Spectrum Scale (GPFS) 日常运维命令大全

目录 1. 集群管理命令 1.1 集群启动与停止 1.2 节点管理 1.3 集群配置查看与修改 2. 文件系统管理 2.1 文件系统创建与删除 2.2 文件系统挂载与卸载 2.3 文件系统属性修改 3. 存储池与磁盘管理 3.1 存储池管理 3.2 物理磁盘管理 3.3 磁盘故障处理 4. 性能监控与调优…...

IDE 使用技巧与插件推荐

在现代软件开发中,集成开发环境(IDE)不仅是代码编辑器,更是提升开发效率和代码质量的强大平台。本文将从基础使用技巧、高级功能、插件生态、定制化配置及实战案例五大方面,帮助你全面掌握 IDE,提高编程体验…...

【MySQL】使用文件进行交互

目录 准备工作 1.从文本文件中读取数据(导入) 1.1.CSV 文件 1.2.设置导入导出的路径 1.3.导入文件 1.4.将数据写入文本文件(导出) 2.从文件中读取并执行SQL命令 2.1.通过mysql监视器执行编写在文件里面的SQL语句 2.2.通过…...

Redis 学习笔记 5:分布式锁

Redis 学习笔记 5:分布式锁 在前文中学习了如何基于 Redis 创建一个简单的分布式锁。虽然在大多数情况下这个锁已经可以满足需要,但其依然存在以下缺陷: 事实上一般而言,我们可以直接使用 Redisson 提供的分布式锁而非自己创建。…...

【硬核数学】2. AI如何“学习”?微积分揭秘模型优化的奥秘《从零构建机器学习、深度学习到LLM的数学认知》

在上一篇中,我们探索了线性代数如何帮助AI表示数据(向量、矩阵)和变换数据(矩阵乘法)。但AI的魅力远不止于此,它最核心的能力是“学习”——从数据中自动调整自身,以做出越来越准确的预测或决策…...

[Java][Leetcode middle] 151. 反转字符串中的单词

思路挺简单的 自己想的,步骤挺复杂的 先统计处开头和结尾的空格数跳过开头这些空格,将单词放到数组中统计最后一个可能漏过的单词(例如:“hello word”,没有空格退出)倒序输出 public String reverseWor…...

力扣每日一题5-18

class Solution { public int colorTheGrid(int m, int n) { // 每一列可能的状态总数 每个单元有3可能 int totalState 1; for (int i 0; i < m; i) totalState * 3; // pre[k] 代表前一轮dp 状态为k 的方案总数 int [] pre new int [totalState]; // 初始化合法填色 的…...

leetcode 74. Search a 2D Matrix

题目描述 要求时间复杂度必须是log(m*n)。那么对每一行分别执行二分查找就不符合要求&#xff0c;这种做法的时间复杂度是m*log(n)。 方法一&#xff0c;对每一行分别执行二分查找&#xff1a; class Solution { public:bool searchMatrix(vector<vector<int>>&a…...