学习笔记08——ConcurrentHashMap实现原理及源码解析
1. 概述
为什么需要ConcurrentHashMap?
-
解决HashMap线程不安全问题:多线程put可能导致死循环(JDK7)、数据覆盖(JDK8)
-
优化HashTable性能:通过细粒度锁替代全局锁,提高并发度
对比表
| 特性 | HashMap | HashTable | ConcurrentHashMap |
|---|---|---|---|
| 线程安全 | 否 | 是 | 是 |
| 锁粒度 | 无锁 | 全局锁 | 分段锁/CAS+synchronized |
| 并发性能 | 高 | 极低 | 高 |
| Null键/值 | 允许 | 不允许 | 不允许 |
JDK版本差异
-
JDK7:基于Segment分段锁(默认16段)
-
JDK8+:数组+链表+红黑树,使用CAS + synchronized锁头节点
2. 线程安全实现机制
JDK8的锁优化
final V putVal(K key, V value, boolean onlyIfAbsent) {// ...for (Node<K,V>[] tab = table;;) {Node<K,V> f; int n, i, fh;if (tab == null || (n = tab.length) == 0)tab = initTable();else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {// CAS插入新节点(无锁)if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))break;}else if ((fh = f.hash) == MOVED)tab = helpTransfer(tab, f);else {synchronized (f) { // 锁住链表头节点// 处理链表/红黑树插入}}}// ...
}
-
CAS:用于无竞争情况下的快速插入(如空桶)
-
synchronized锁头节点:仅锁定当前哈希桶,不影响其他桶操作
3. 核心数据结构
Node节点结构
static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;volatile V val;volatile Node<K,V> next;// ...
}
-
volatile修饰:保证可见性,确保读线程能立即看到更新
-
红黑树节点:
TreeNode继承Node,用于处理长链表(阈值=8)
扩容机制
-
触发条件:元素数量超过
sizeCtl -
多线程协助:通过
ForwardingNode标记正在迁移的桶,其他线程可参与迁移
4. 关键源码解析
以下是对 ConcurrentHashMap 核心源码的深度解读,结合 JDK8 的实现进行分析:
4.1核心方法源码解析
1. 初始化:initTable()
private final Node<K,V>[] initTable() {Node<K,V>[] tab; int sc;while ((tab = table) == null || tab.length == 0) {// sizeCtl < 0 表示其他线程正在初始化if ((sc = sizeCtl) < 0)Thread.yield(); // 让出 CPU,等待初始化完成else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) { // CAS 抢锁try {// 双重检查,防止重复初始化if ((tab = table) == null || tab.length == 0) {int n = (sc > 0) ? sc : DEFAULT_CAPACITY;Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];table = tab = nt;sc = n - (n >>> 2); // 计算扩容阈值(0.75n)}} finally {sizeCtl = sc; // 释放锁,设置阈值}break;}}return tab;
}
-
CAS 抢锁:通过
sizeCtl标记初始化状态(-1 表示初始化中)。 -
双重检查:避免多线程重复初始化。
-
负载因子固定为 0.75:通过
sc = n - (n >>> 2)实现。
2. put 方法:putVal()
final V putVal(K key, V value, boolean onlyIfAbsent) {if (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode()); // 计算哈希(高位参与运算)int binCount = 0;for (Node<K,V>[] tab = table;;) {Node<K,V> f; int n, i, fh;if (tab == null || (n = tab.length) == 0)tab = initTable(); // 懒初始化else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { // 桶为空if (casTabAt(tab, i, null, new Node<>(hash, key, value))) // CAS 插入break;} else if ((fh = f.hash) == MOVED) // 正在扩容tab = helpTransfer(tab, f); // 协助扩容else {V oldVal = null;synchronized (f) { // 锁住头节点if (tabAt(tab, i) == f) { // 再次验证头节点未变if (fh >= 0) { // 链表节点binCount = 1;for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {oldVal = e.val;if (!onlyIfAbsent)e.val = value; // 更新值break;}Node<K,V> pred = e;if ((e = e.next) == null) {pred.next = new Node<>(hash, key, value); // 追加到链表尾部break;}}} else if (f instanceof TreeBin) { // 红黑树节点Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;}}}}if (binCount != 0) {if (binCount >= TREEIFY_THRESHOLD) // 链表长度 >=8treeifyBin(tab, i); // 可能树化if (oldVal != null)return oldVal;break;}}}addCount(1L, binCount); // 更新元素计数return null;
}
关键逻辑:
-
哈希计算:
spread()方法通过(h ^ (h >>> 16)) & HASH_BITS保证哈希值为正数。 -
CAS 插入空桶:若桶为空,直接通过
casTabAt插入新节点(无锁优化)。 -
锁头节点处理冲突:对非空桶使用
synchronized锁定头节点,处理链表或红黑树。 -
树化条件:链表长度 >=8 且数组长度 >=64 时树化,否则优先扩容。
-
并发扩容协作:若发现桶正在迁移(
MOVED标记),当前线程会协助迁移。
3. 扩容机制:transfer()
private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {int n = tab.length, stride;// 计算每个线程处理的桶区间(最小 16)if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)stride = MIN_TRANSFER_STRIDE;if (nextTab == null) { // 初始化新数组try {Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];nextTab = nt;} catch (Throwable ex) { sizeCtl = Integer.MAX_VALUE; return; }nextTable = nextTab;transferIndex = n; // 迁移起点为旧数组末尾}// 多线程协同迁移逻辑ForwardingNode<K,V> fwd = new ForwardingNode<>(nextTab);boolean advance = true;boolean finishing = false;for (int i = 0, bound = 0;;) {Node<K,V> f; int fh;while (advance) {int nextIndex, nextBound;if (--i >= bound || finishing)advance = false;else if ((nextIndex = transferIndex) <= 0) {i = -1;advance = false;} else if (U.compareAndSwapInt(this, TRANSFERINDEX, nextIndex,nextBound = (nextIndex > stride ? nextIndex - stride : 0))) {bound = nextBound;i = nextIndex - 1;advance = false;}}// 实际迁移逻辑(略,处理链表/树拆分到新数组)}
}
核心设计:
-
多线程任务分配:通过
transferIndex全局指针分配迁移区间(类似“工作窃取”)。 -
ForwardingNode 占位符:迁移中的桶会被标记为
ForwardingNode,读请求会转发到新数组。 -
链表拆分优化:根据哈希值的高位决定节点留在旧桶还是迁移到新桶(
newIndex = oldIndex + oldCap)。
4. 无锁读:get()
public V get(Object key) {Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;int h = spread(key.hashCode());if ((tab = table) != null && (n = tab.length) > 0 &&(e = tabAt(tab, (n - 1) & h)) != null) {if ((eh = e.hash) == h) {if ((ek = e.key) == key || (ek != null && key.equals(ek)))return e.val; // 命中头节点} else if (eh < 0) // 特殊节点(红黑树或 ForwardingNode)return (p = e.find(h, key)) != null ? p.val : null;while ((e = e.next) != null) { // 遍历链表if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek))))return e.val;}}return null;
}
无锁保障:
-
tabAt()使用Unsafe.getObjectVolatile保证读取最新内存值。 -
链表遍历期间依赖
volatile修饰的next指针保证可见性。 -
遇到
ForwardingNode时自动跳转到新数组查询。
4.2.关键优化总结
| 优化点 | 实现方式 |
|---|---|
| 锁粒度 | 仅锁单个桶的头节点(JDK8),替代 JDK7 的分段锁 |
| CAS 无锁插入 | 空桶通过 casTabAt 直接插入,避免锁竞争 |
| 多线程协作扩容 | 通过 ForwardingNode 和 transferIndex 分配任务区间 |
| 计数优化 | 使用 CounterCell[] 分散竞争,避免 size() 成为性能瓶颈 |
| 红黑树退化机制 | 当树节点 <=6 时退化为链表,避免频繁树化开销 |
4.3源码分析的思考题
-
为什么在链表长度超过 8 时可能选择扩容而不是直接树化?
-
数组较短时(<64),扩容能更有效减少哈希冲突。
-
-
如何保证扩容期间读操作的正确性?
-
通过
ForwardingNode将读请求转发到新数组,写操作会等待迁移完成。
-
-
size() 方法为什么不是精确值?
-
高并发场景下精确统计代价过高,采用分片计数(
CounterCell)近似值。
-
5. 并发操作分析
扩容期间读写协调
-
读操作:遇到
ForwardingNode时转到新表查询 -
写操作:协助迁移当前桶后再执行插入
线程协作扩容
private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {// 每个线程处理一个区间,完成后再领取新区间
}
-
通过
stride步长划分任务区间 -
使用
transferIndex指针协调多线程任务分配
6. 总结
设计亮点
-
锁分离:降低锁竞争概率
-
乐观锁优先:CAS无锁化尝试
-
粒度细化:从分段锁到桶级别锁
-
无锁读:volatile变量保证可见性
7.面试回答模板
面试官:请说一下ConcurrentHashMap的实现原理。 回答:
ConcurrentHashMap在JDK1.8中采用了数组+链表/红黑树的结构,通过CAS和synchronized实现高并发。
写操作:如果桶为空,用CAS插入头节点;否则锁住头节点处理链表或红黑树。
读操作:完全无锁,依赖volatile保证可见性。
扩容:多线程协作迁移数据,通过ForwardingNode标记已处理的桶。
线程安全:锁粒度细化到单个桶,结合CAS减少竞争。 对比HashTable,它的并发性能更高,且支持更高的并发度。
8.源码分析技巧
-
关注核心方法:
putVal、get、transfer(扩容)、helpTransfer。 -
调试参数:通过
-XX:+PrintConcurrentLocks观察锁竞争情况。 -
结合JMM:分析
volatile变量(如table、sizeCtl)的内存可见性保证。
9.常见面试题
以下是关于 Java ConcurrentHashMap 的常见面试题及其详细解答,涵盖底层实现、线程安全机制、性能优化等核心内容:
1. ConcurrentHashMap 如何实现线程安全?
回答要点:
-
JDK7 的分段锁(Segment): 将整个哈希表分成多个段(默认 16 段),每个段独立加锁,不同段的操作可以并发执行。
-
优点:降低锁粒度,减少竞争。
-
缺点:内存占用较高(每个段独立维护数组),并发度受段数限制。
-
-
JDK8 的 CAS + synchronized 锁优化:
-
CAS 无锁插入:当桶为空时,直接通过 CAS 插入新节点,避免加锁。
-
synchronized 锁头节点:当桶非空时,仅锁住链表或红黑树的头节点,锁粒度细化到单个桶。
-
扩容协作:多线程可以协同迁移数据,减少扩容时间。
-
2. ConcurrentHashMap 与 HashMap、HashTable 的区别?
| 特性 | HashMap | HashTable | ConcurrentHashMap |
|---|---|---|---|
| 线程安全 | 非线程安全 | 全局锁(方法级同步) | CAS + 细粒度锁(桶级别) |
| Null 键/值 | 允许 | 禁止 | 禁止 |
| 性能 | 高(无锁) | 极低(全局锁) | 高(并发优化) |
| 迭代器一致性 | 快速失败 | 快速失败 | 弱一致性 |
| 实现机制 | 数组+链表+红黑树 | 数组+链表 | 数组+链表+红黑树(JDK8+) |
3. JDK7 和 JDK8 的 ConcurrentHashMap 实现差异?
-
JDK7:
-
基于 分段锁(Segment),每个段类似一个独立的哈希表。
-
默认 16 段,并发度固定,无法动态扩展。
-
内存占用较高(每个段维护独立的数组)。
-
-
JDK8:
-
抛弃分段锁,采用 CAS + synchronized 锁头节点,锁粒度细化到单个桶。
-
引入 红黑树,当链表长度 >=8 且数组长度 >=64 时树化,提升查询效率。
-
内存利用率更高(共享一个数组),并发度动态扩展。
-
支持 多线程协作扩容,迁移效率更高。
-
4. ConcurrentHashMap 的 put 方法流程?
-
计算哈希:
spread(key.hashCode())(保证哈希值为正数)。 -
懒初始化:若数组为空,调用
initTable()初始化。 -
定位桶:
(n-1) & hash计算桶下标。 -
CAS 插入空桶:若桶为空,直接通过 CAS 插入新节点。
-
处理哈希冲突:
-
若桶正在迁移(
ForwardingNode),当前线程协助迁移。 -
非空桶锁住头节点,处理链表或红黑树的插入/更新。
-
-
树化检查:链表长度 >=8 时可能触发树化。
-
更新计数:调用
addCount()更新元素总数(基于CounterCell[]分片计数)。
5. ConcurrentHashMap 的 size() 方法为什么不是完全精确的?
-
分片计数优化: 使用
CounterCell[]数组分散计数更新,避免多线程竞争同一变量。-
当无竞争时,直接更新
baseCount。 -
当检测到竞争时,使用
CounterCell分片统计,最终结果为baseCount + ∑CounterCell[i]。
-
-
设计权衡: 高并发场景下,精确统计需要全局锁,性能代价过高。
size()返回的是一个近似值,但实际开发中足够使用。
6. 如何保证 get() 操作的无锁和高性能?
-
volatile 变量: 桶数组和节点的
val、next字段用volatile修饰,保证可见性。 -
无锁读设计:
-
tabAt()使用Unsafe.getObjectVolatile直接读取内存最新值。 -
遍历链表或红黑树时不加锁,依赖
volatile保证数据可见性。
-
-
扩容期间的读操作: 遇到
ForwardingNode时,自动跳转到新数组查询数据。
7. ConcurrentHashMap 的扩容机制如何实现?
核心步骤:
-
触发条件:元素数量超过
sizeCtl(扩容阈值 = 0.75 * 数组长度)。 -
多线程协作:
-
首个线程创建新数组(长度翻倍),并分配迁移任务区间。
-
其他线程通过
transferIndex领取迁移任务(步长stride)。
-
-
迁移逻辑:
-
将旧数组的桶拆分为高低位链表,高位链表迁移到
旧下标 + 旧容量的位置。 -
迁移完成的桶用
ForwardingNode占位,表示已处理。
-
-
读写协调:
-
读操作:遇到
ForwardingNode时跳转到新数组查询。 -
写操作:先协助迁移当前桶,再执行插入。
-
8. 链表何时会转为红黑树?何时会退化为链表?
-
树化条件:
-
链表长度 >=8(
TREEIFY_THRESHOLD)。 -
数组长度 >=64(
MIN_TREEIFY_CAPACITY),否则优先扩容。
-
-
退化条件:
-
红黑树节点数 <=6(
UNTREEIFY_THRESHOLD)时退化为链表。
-
-
设计目的: 平衡查询效率和空间占用,避免极端情况下的性能问题。
9. ConcurrentHashMap 为什么不允许 Null 键或 Null 值?
-
歧义性问题:
get(key)返回null时,无法区分是键不存在还是键对应的值为null。 -
线程安全风险: 若允许
null,可能因并发操作导致隐式的NullPointerException(如containsKey(key)和get(key)之间的竞争)。 -
设计一致性:
ConcurrentHashMap的设计目标是为并发场景提供明确的语义,禁止null可减少不确定性。
10. ConcurrentHashMap 的迭代器是强一致性还是弱一致性?
-
弱一致性: 迭代器在遍历时不会锁定整个哈希表,可能反映部分已完成的更新操作。
-
迭代过程中可能看到新增、删除或修改的键值对,但不保证完全一致。
-
设计目的是避免迭代期间阻塞其他线程,提升并发性能。
-
-
对比其他集合:
HashMap的迭代器是快速失败的(fail-fast),而ConcurrentHashMap的迭代器是安全的(fail-safe)。
11. 为什么 JDK8 改用 synchronized 而不是 ReentrantLock?
-
锁粒度细化:
synchronized在 JDK6 后进行了大量优化(如偏向锁、轻量级锁),性能与ReentrantLock接近。 -
内存消耗:
ReentrantLock需要额外维护AQS队列,内存开销更大。 -
代码简洁性:
synchronized语法更简洁,无需手动释放锁,减少编码错误。
12. ConcurrentHashMap 是否完全线程安全?
-
基本操作线程安全:
put、get、remove等单操作是原子的,线程安全。 -
组合操作非原子:
if (!map.containsKey(key)) map.put(key, value); // 非原子操作
此类组合操作需使用
putIfAbsent()或外部同步。 -
迭代器弱一致性: 迭代期间可能看到其他线程的修改,但不会抛出
ConcurrentModificationException。
13. 如何理解 sizeCtl 字段的作用?
sizeCtl 是一个控制状态变量,具体含义:
-
>0:表示下一次扩容的阈值(0.75 * 当前容量)。
-
=0:默认初始状态。
-
=-1:表示哈希表正在初始化。
-
<-1:表示正在扩容,高 16 位表示扩容标识戳,低 16 位表示参与扩容的线程数 +1。
14. ConcurrentHashMap 的应用场景?
-
高并发缓存:如缓存用户会话信息、商品库存等。
-
实时统计:如多线程计数(需结合
addCount()机制)。 -
替代 HashTable:所有需要线程安全哈希表的场景,性能更优。
-
分布式计算:如 MapReduce 任务中的局部结果聚合。
15. 如何设计一个线程安全的哈希表?
-
锁粒度优化: 从全局锁 → 分段锁 → 桶级别锁,逐步减少竞争。
-
无锁化尝试: 优先使用 CAS 处理无竞争场景(如空桶插入)。
-
并发扩容协作: 允许多线程协同迁移数据,提升扩容效率。
-
数据结构优化: 引入红黑树平衡查询效率,动态退化避免空间浪费。
相关文章:
学习笔记08——ConcurrentHashMap实现原理及源码解析
1. 概述 为什么需要ConcurrentHashMap? 解决HashMap线程不安全问题:多线程put可能导致死循环(JDK7)、数据覆盖(JDK8) 优化HashTable性能:通过细粒度锁替代全局锁,提高并发度 对比…...
数据集笔记:NUSMods API
1 介绍 NUSMods API 包含用于渲染 NUSMods 的数据。这些数据包括新加坡国立大学(NUS)提供的课程以及课程表的信息,还包括上课地点的详细信息。 可以使用并实验这些数据,它们是从教务处提供的官方 API 中提取的。 该 API 由静态的…...
SpringBoot新闻推荐系统设计与实现
随着信息时代的快速发展,新闻推荐系统成为用户获取个性化内容的重要工具。本文将介绍一个幽络源的基于SpringBoot开发的新闻推荐系统,该系统功能全面,操作简便,能够满足管理员和用户的多种需求。 管理员模块 管理员模块为系统管…...
谷歌推出PaliGemma 2 mix:用于多任务的视觉语言模型,开箱即用。
去年 12 月,谷歌推出了 PaliGemma 2 ,这是Gemma系列中的升级版视觉语言模型。该版本包含不同大小(3B、10B 和 28B 参数)的预训练检查点,可轻松针对各种视觉语言任务和领域进行微调,例如图像分割、短视频字幕…...
深入浅出Spring Boot框架:从入门到精通
引言 在现代软件开发中,Java 语言及其生态系统一直是构建企业级应用的首选之一。Spring Boot 是 Java 社区中最具影响力的项目之一,它继承了 Spring 框架的优点,并通过简化配置和加速开发流程,使得开发者能够更加专注于业务逻辑的…...
Spring Boot spring-boot-maven-plugin 参数配置详解
一 spring-boot-maven-plugin 插件的5个Goals spring-boot:repackage,默认goal。在mvn package之后,再次打包可执行的jar/war,同时保留mvn package生成的jar/war为.origin;重新打包存在的jar或者war包从而使他们可以在命令行使用…...
linux中断调用流程(arm)
文章目录 ARM架构下Linux中断处理全流程解析:从硬件触发到驱动调用 ⚡**一、中断触发与硬件层响应** 🔌**1. 设备触发中断** 📡 **二、CPU阶段:异常入口与上下文处理** 🖥️**1. 异常模式切换** 🔄**2. 跳转…...
考研复试问题总结-数据结构(1)
1. 说一下你对数据结构的理解 我觉得数据结构不仅仅是存数据的“容器”,更是一种思维方式。其实,在我们写程序时,经常会遇到各种各样的数据操作需求,而不同的数据结构能解决问题的效率和方式都不一样,所以选择合适的数…...
250301-OpenWebUI配置DeepSeek-火山方舟+硅基流动+联网搜索+推理显示
A. 最终效果 B. 火山方舟配置(一定要点击添加) C. 硅基流动配置(最好要点击添加,否则会自动弹出所有模型) D. 联网搜索配置 E. 推理过程显示 默认是没有下面的推理过程的显示的 设置步骤: 在Functions函…...
RuoYi框架介绍,以及如何基于Python使用RuoYi框架
若依框架(RuoYi)是一款基于Spring Boot和Vue.js的开源快速开发平台,广泛应用于企业级应用开发。它提供了丰富的功能模块和代码生成工具,帮助开发者快速搭建后台管理系统。 主要特点 前后端分离:前端采用Vue.js&#x…...
【算法】图论 —— Floyd算法 python
洛谷 B3647 【模板】Floyd 题目描述 给出一张由 n n n 个点 m m m 条边组成的无向图。 求出所有点对 ( i , j ) (i,j) (i,j) 之间的最短路径。 输入格式 第一行为两个整数 n , m n,m n,m,分别代表点的个数和边的条数。 接下来 m m m 行,每行三…...
2.数据结构:2.最大异或对
数据结构 2.数据结构:1.Tire 字符串统计 当前题 最大异或对 #include<algorithm> #include<cstring> #include<iostream>using namespace std;const int N100010,M31*N;// M 表示节点个数,每一个数最多有 31 位int n; int a[N]; i…...
剑指 Offer II 031. 最近最少使用缓存
comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20031.%20%E6%9C%80%E8%BF%91%E6%9C%80%E5%B0%91%E4%BD%BF%E7%94%A8%E7%BC%93%E5%AD%98/README.md 剑指 Offer II 031. 最近最少使用缓存 题目描述 运用所掌握的…...
Windows 11【1001问】查看Windows 11 版本的18种方法
随着技术的飞速发展,操作系统作为连接硬件与软件的核心桥梁,其版本管理和更新变得尤为重要。对于用户而言,了解自己设备上运行的具体Windows 11版本不仅有助于优化系统性能,还能确保安全性和兼容性。然而,不同场景和需…...
小程序性能优化-预加载
在微信小程序中,数据预加载是提升用户体验的重要优化手段。以下是处理数据预加载的完整方案: 一、预加载的适用场景 跳转页面前的数据准备 如从列表页进入详情页前,提前加载详情数据首屏加载后的空闲时间 在首页加载完成后,预加载…...
vue3中展示markdown格式文章的三种形式
一、安装 # 使用 npm npm i kangc/v-md-editor -S# 使用yarn yarn add kangc/v-md-editor二、三种实现形式 1、编辑器的只读模式 main.ts文件中配置: import VMdEditor from kangc/v-md-editor; import kangc/v-md-editor/lib/style/base-editor.css;const app …...
(视频教程)Compass代谢分析详细流程及python版-R语言版下游分析和可视化
不想做太多的前情解说了,有点累了,做了很久的内容,包括整个分析,从软件安装和报错解决到后期下游python版-R语言版下游分析和可视化!单细胞代谢分析我们写过很多了,唯独少了最“高级”的compass,…...
文件描述符与重定向
1. open系统调用 在 Linux 中, open() 系统调用用于打开一个文件或设备,并返回一个文件描述符,通过该描述符可以进行文件读写操作。open() 可以用于创建新文件或打开已存在的文件,具体行为取决于传递给它的参数。 需要包含的头文件…...
为什么深度学习选择Tensor而非NumPy数组?核心优势深度解析
简短总结: 支持 GPU 加速:Tensor 提供对 GPU 的原生支持,能够有效加速计算,而 NumPy 则通常只能在 CPU 上运行。支持自动求导:深度学习模型的训练依赖于参数的优化,而 Tensor 提供了自动求导功能ÿ…...
python把html网页转换成pdf标题没有乱码,正文都乱码
在使用Python将HTML网页转换成PDF时,遇到标题没有乱码但正文乱码的问题,通常是由于字符编码处理不当或字体支持问题导致的。以下是一些可能的原因和解决方案: 原因分析 字符编码不匹配: HTML文件的编码与PDF转换工具或库所使用的…...
基于fast-whisper模型的语音识别工具的设计与实现
目录 摘 要 第1章 绪 论 1.1 论文研究主要内容 1.1.1模型类型选择 1.1.2开发语言的选择 1.2 国内外现状 第2章 关键技术介绍 2.1 关键性开发技术的介绍 2.1.1 Faster-Whisper数据模型 2.1.2 Django 第3章 系统分析 3.1 构架概述 3.1.1 功能构架 3.1.2 模块需求描述 3.2 系统开…...
详解:事务注解 @Transactional
创作内容丰富的干货文章很费心力,感谢点过此文章的读者,点一个关注鼓励一下作者,激励他分享更多的精彩好文,谢谢大家! Transactional 是 Spring Framework 中常用的注解之一,它可以被用于管理事务。通过使用…...
场内、场外期权怎么开户?期权佣金是多少?
期权交易需要一定的知识和经验,以有效管理风险和制定策略。 场内期权开户(以50ETF为例) 场内期权开户的各种方式大差不差,咱们就先以50ETF期权为例子看下。 场内期权开户条件包括: 首先是资金的要求,50万…...
Linux:进程概念
目录 1 冯诺依曼体系 2 操作系统(Operator System) 3 如何理解管理 3.1计算机管理硬件 3.2 管理逻辑图 3.3 怎样管理 4 什么是进程? 5 查看进程 5.1 ps ajx显示所有进程信息 5.2 /proc(内存文件系统) 5.2.1 ls /proc/PID 5.2.2 ls /proc/PID -al 5…...
Rabbit MQ 高频面试题【刷题系列】
文章目录 一、公司生产环境用的什么消息中间件?二、Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优缺点?三、解耦、异步、削峰是什么?四、消息队列有什么缺点?五、RabbitMQ一般用在什么场景?六、简单说RabbitMQ有哪些角…...
破解密码防线:渗透测试中的密码攻击手法汇总
密码是网络安全中的一道重要防线,然而,若密码策略不严密,往往会为攻击者提供可乘之机。本文将简要介绍渗透测试中关于密码的几种常见攻击思路和手法。 1. 确认使用默认及常见的账号密码 在渗透测试的初期,攻击者通常会尝试使用系…...
大模型在白血病诊疗全流程风险预测与方案制定中的应用研究
目录 一、绪论 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目的与内容 二、大模型技术与白血病相关知识 2.1 大模型技术原理与特点 2.2 白血病的病理生理与诊疗现状 三、术前风险预测与手术方案制定 3.1 术前数据收集与预处理 3.2 大模型预测术前风险 3.3 根据…...
5-2JVM内存的各种应用
一、堆区(Heap)——对象实例的存储池 实际应用场景: 对象实例化:所有通过 new 关键字创建的对象实例均存储在堆中。例如: java Person person new Person(“张三”); // person对象实例分配在堆区1,4,6 大对象直…...
【NLP 28、一文速通NLP文本分类任务 —— 深度学习】
目录 一、深度学习 — pipeline 流水线 1.配置文件 config.py Ⅰ、路径相关 Ⅱ、模型相关 Ⅲ、训练相关 2.数据加载 loader.py Ⅰ、类初始化 Ⅱ、加载数据并预处理 Ⅲ、文本编码 Ⅳ、对输入序列截断或填充 Ⅴ、返回数据长度 Ⅵ、返回对应索引位置元素 Ⅶ、加载词表 Ⅷ、封装数据…...
nvidia驱动更新,centos下安装openwebui+ollama(非docker)
查看centos内核版本 uname -a cat /etc/redhat-release下载对应的程序(这个是linux64位版本通用的) https://cn.download.nvidia.cn/tesla/550.144.03/NVIDIA-Linux-x86_64-550.144.03.run cudnn想办法自己下一下,我这里是12.x和11.x通用的…...
