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

JAVA集合之Map >>HashMap/Hashtable/TreeMap/LinkedHashMap结构

Map 是一种键-值对(key-value)集合,键不可以重复,值可以重复。常见的实现类有:HashMap、Hashtable、TreeMap、LinkedHashMap等。

HashMap&Hashtable

HashMap:数据结构为哈希表,允许使用 null 值和 null 键,线程不同步。Hashtable与HashMap差不多,但是线程同步的,且不可以存入null键null值。

JDK1.7的Hashmap 结构是,数组+链表的形式进行存储的。存入时通过KEY的hashCode % capacity(数组的容量),找到数组位置,每个数组位置保存的都是一个链表结构,用于存储一个或多个对象。

JDK1.8后Hashmap结构进行优化,数组+链表+红黑树。当链表长度达到一定阈值时,链表结构会变为红黑树(当链表阈值长度=8时,会进入红黑树判断:当数组长度<64时,会优先扩容,当数组长度>= 64时才转红黑树),红黑树的优点在于,平衡链表结构的算法,提升查询性能。具体参考:红黑树算法。

JDK1.8为了避免多线程数据冲突及死锁的做了优化(去除了rehash),使用了高低位运算,来迁移数据,低位,直接迁移到原来的位置,高位,迁移到扩容后的位置(i + 原来Hashmap 数组的大小)。

JDK1.8对HashMap Get或Put寻址取模算法(hashCode % capacity)进行了优化,将其改为了hash & (length-1) 这种二进制的位运算进行判断,计算结果等同于取模算法,但是效率高于它。这种运算需要保证length-1的二进制码都为1,才能将元素均匀的分布到数组下标中,所以在hashmap底层代码内,规定了数组的容量必须是2的指数次幂(因为只有2的指数次幂 -1的二进制编码才全部为1),才能保证保存对象不会发生数组越界。具体参考:HashMap 底层源码。

hash碰撞

上面介绍了如何找到对应的下标进行保存对象,但是在操作多个对象时,是有可能在计算后得到相同的数组下标,也就是我们的hash碰撞,这个时候hashmap就会把相同下标的对象以链表的方式进行存储,当链表的长度达到一定的阈值(默认8)时,就会改用红黑树就行保存,红黑树的优点在于,平衡链表结构的算法,提升查询性能。链表查询的时间复杂度为O(n),红黑树的时间复杂的为O(logn)。

加载因子为0.75的作用

Hash存储对象,并不能保证利用率是100%(每个数组下标都能存放数据),所以为了每个对象能均匀散列在数组中,设置了加载因子为0.75(如,HashMap 的初始化容量是16,载因子为0.5,那么当HashMap中有16*0.5=8个元素时,HashMap 就会进行扩容)。0.75是选择了时间,与空间之间选择平衡。如果大于0.75,利用率高了,但是HashMap发生hash碰撞的几率就会变高,hash碰撞就会导致我们的链表或红黑树节点深度更深,所以性能会相对下降。如果小于0.75 ,那么我们的空间的利用率也就会变的更低。所以 hashMap 建议为默认的 0.75 在时间与空间之间的平衡选择。

参考源码:

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {/*** The default initial capacity - MUST be a power of two.* 翻译:默认初始容量-必须是2的幂*/static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16/*** 最大容量 1<<30.*/static final int MAXIMUM_CAPACITY = 1 << 30;/*** The load factor used when none specified in constructor.* 加载因子默认0.75*/static final float DEFAULT_LOAD_FACTOR = 0.75f;/*** 链表转成红黑树的阈值:当链表长度 > 该值时*/static final int TREEIFY_THRESHOLD = 8;/*** 红黑树转为链表的阈值(当原有的红黑树内数量 < 6时,则将红黑树转换成链表)*/static final int UNTREEIFY_THRESHOLD = 6;/*** 最小树形化容量阈值:当哈希表中数组的容量>该值时+链表长度>TREEIFY_THRESHOLD则链表转红黑树*/static final int MIN_TREEIFY_CAPACITY = 64;/*** 记录HashMap的结构修改次数*/transient int modCount;/*** The number of key-value mappings contained in this map.*/transient int size;/*** The next size value at which to resize (capacity * load factor).* 翻译: 记录当map存储了多少个数组元素时开始扩容 (capacity * load factor)*/int threshold;/*** Constructs an empty <tt>HashMap</tt> with the default initial capacity* (16) and the default load factor (0.75).*/public HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted}public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;// 第一次操作,先初始化容量 16 if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 通过hash获取数组元素,如果为空则将元素插入到当前位置if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;// 如果key相同,则e=p ,下面代码中会通过 e 将新元素覆盖掉就旧元素if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))e = p;// 判断是否是 TreeNode else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {// 遍历以链表或红黑树方式存放元素for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// 如果链表大小>=TREEIFY_THRESHOLD 则进入扩容或转红黑树逻辑if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st//扩容或转红黑树的方法treeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);    //使用LinkHashMap时会进行回调的方法return oldValue;}}++modCount;//当map存储的数组个数大于 threshold(capacity * load factor) 开始扩容if (++size > threshold)resize(); //扩容代码不贴,可以自行源码中参考   afterNodeInsertion(evict); //使用LinkHashMap时会进行回调的方法return null;}/*** 扩容或转红黑树方法逻辑*/final void treeifyBin(Node<K,V>[] tab, int hash) {int n, index; Node<K,V> e;// 数组长度如果小于 MIN_TREEIFY_CAPACITY 则进行扩容if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)resize();// 转为红黑树else if ((e = tab[index = (n - 1) & hash]) != null) {TreeNode<K,V> hd = null, tl = null;do {TreeNode<K,V> p = replacementTreeNode(e, null);if (tl == null)hd = p;else {p.prev = tl;tl.next = p;}tl = p;} while ((e = e.next) != null);if ((tab[index] = hd) != null)hd.treeify(tab);}}// Create a regular (non-tree) nodeNode<K,V> newNode(int hash, K key, V value, Node<K,V> next) {return new Node<>(hash, key, value, next);}// For conversion from TreeNodes to plain nodesNode<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {return new Node<>(p.hash, p.key, p.value, next);}/*** 一般用户在链表时使用的结构*/static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;V value;Node<K,V> next;Node(int hash, K key, V value, Node<K,V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}public final K getKey()        { return key; }public final V getValue()      { return value; }public final String toString() { return key + "=" + value; }public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue;}public final boolean equals(Object o) {if (o == this)return true;if (o instanceof Map.Entry) {Map.Entry<?,?> e = (Map.Entry<?,?>)o;if (Objects.equals(key, e.getKey()) &&Objects.equals(value, e.getValue()))return true;}return false;}}/*** 转红黑树时使用的结构*/static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {TreeNode<K,V> parent;  // red-black tree linksTreeNode<K,V> left;TreeNode<K,V> right;TreeNode<K,V> prev;    // needed to unlink next upon deletionboolean red;TreeNode(int hash, K key, V val, Node<K,V> next) {super(hash, key, val, next);}......下面代码太多,可以自行源码中查看}}

上面源码中,根据put流程说明,通过源码跟进,我们就可以看出HashMap的结构、hash碰撞时如何保存、扩容逻辑、什么时候开始转红黑树、及一些重要参数的作用等。

TreeMap

TreeMap:基于红黑色树的顺序访问的Map,与HashMap区别在于HashMap中的元素是没有顺序的,而TreeMap中所有的元素都是有某一固定顺序的。TreeMap继承SortedMap类,他保持键的有序顺序,用于给map集合中的键进行排序(排序方法和TreeSet一样,实现comparable 或comparator 接口)

参考源码:

public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{/*** 排序接口*/private final Comparator<? super K> comparator;private transient Entry<K,V> root;public V put(K key, V value) {Entry<K,V> t = root;//如果root第一个节点为空,则将元素保存到rootif (t == null) {//为插入节点进行排序compare(key, key); // type (and possibly null) checkroot = new Entry<>(key, value, null);size = 1;modCount++;return null;}int cmp;Entry<K,V> parent;// split comparator and comparable pathsComparator<? super K> cpr = comparator;// comparator 非空则使用 comparator 判断排序if (cpr != null) {// 基于根节点遍历,通过左小,右大的方式存入到树节点中(注意:最后字节点会插入null,下面代码会用补充)do {parent = t;cmp = cpr.compare(key, t.key);if (cmp < 0)t = t.left;else if (cmp > 0)t = t.right;elsereturn t.setValue(value);} while (t != null);}// comparator 为空,则使用Comparable 判断排序,其他逻辑与上面差不多else {if (key == null)throw new NullPointerException();@SuppressWarnings("unchecked")Comparable<? super K> k = (Comparable<? super K>) key;do {parent = t;cmp = k.compareTo(t.key);if (cmp < 0)t = t.left;else if (cmp > 0)t = t.right;elsereturn t.setValue(value);} while (t != null);}Entry<K,V> e = new Entry<>(key, value, parent);// 对最后字节点进行补充if (cmp < 0)parent.left = e;elseparent.right = e;//进行红黑树的旋转等操作fixAfterInsertion(e);size++;modCount++;return null;}// 通过两个Key比较来排序,comparator 不存在则使用 Comparablefinal int compare(Object k1, Object k2) {return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2): comparator.compare((K)k1, (K)k2);}static final class Entry<K,V> implements Map.Entry<K,V> {K key;V value;//左子节点Entry<K,V> left;//又子节点Entry<K,V> right;//父节点Entry<K,V> parent;//颜色标记-红色/黑色boolean color = BLACK;/*** Make a new cell with given key, value, and parent, and with* {@code null} child links, and BLACK color.*/Entry(K key, V value, Entry<K,V> parent) {this.key = key;this.value = value;this.parent = parent;}public V setValue(V value) {V oldValue = this.value;this.value = value;return oldValue;}......省略}}

源码中可以看到,TreeMap内部使用的是Entry结构,Entry结构中,又声明了 letf ,right等变量用于保存左、右子节点,color标记颜色(红/黑),源码开始形成的是二叉树,执行了fixAfterInsertion(e);后才生成的红黑树对整个树进行平衡。详见如下fixAfterInsertion源码

public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{//红/黑色标记private static final boolean RED   = false;private static final boolean BLACK = true;//获取颜色private static <K,V> boolean colorOf(Entry<K,V> p) {return (p == null ? BLACK : p.color);}//获取父节点private static <K,V> Entry<K,V> parentOf(Entry<K,V> p) {return (p == null ? null: p.parent);}//设置颜色private static <K,V> void setColor(Entry<K,V> p, boolean c) {if (p != null)p.color = c;}//获取左节点private static <K,V> Entry<K,V> leftOf(Entry<K,V> p) {return (p == null) ? null: p.left;}//获取又节点private static <K,V> Entry<K,V> rightOf(Entry<K,V> p) {return (p == null) ? null: p.right;}/** 向左旋转 */private void rotateLeft(Entry<K,V> p) {if (p != null) {Entry<K,V> r = p.right;p.right = r.left;if (r.left != null)r.left.parent = p;r.parent = p.parent;if (p.parent == null)root = r;else if (p.parent.left == p)p.parent.left = r;elsep.parent.right = r;r.left = p;p.parent = r;}}/**向右旋转 */private void rotateRight(Entry<K,V> p) {if (p != null) {Entry<K,V> l = p.left;p.left = l.right;if (l.right != null) l.right.parent = p;l.parent = p.parent;if (p.parent == null)root = l;else if (p.parent.right == p)p.parent.right = l;else p.parent.left = l;l.right = p;p.parent = l;}}//红黑树平衡设置private void fixAfterInsertion(Entry<K,V> x) {//新节设置为红色x.color = RED;//循环条件=非空&非根节点&x的父节点颜色为红色while (x != null && x != root && x.parent.color == RED) {//判断父节点是否是在左边的节点if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {//获取祖父节点的右子节点Entry<K,V> y = rightOf(parentOf(parentOf(x)));//右叔叔节点为红色,则更新相关颜色if (colorOf(y) == RED) {                    setColor(parentOf(x), BLACK);        //父节点设置为黑色setColor(y, BLACK);                  //叔叔节点置为黑色setColor(parentOf(parentOf(x)), RED);//祖父节点置为红色x = parentOf(parentOf(x));           //将继续循环赋予X,继续循环} else {//如果x在右节点-则进行左旋父节点if (x == rightOf(parentOf(x))) {x = parentOf(x);rotateLeft(x);   //左旋父节点}setColor(parentOf(x), BLACK);        //父节点设置为黑色setColor(parentOf(parentOf(x)), RED);//祖父节点置为红色rotateRight(parentOf(parentOf(x)));  //右旋祖父节点}} else {    //否则是右边的节点 - 其他逻辑与上面的相似Entry<K,V> y = leftOf(parentOf(parentOf(x)));if (colorOf(y) == RED) {setColor(parentOf(x), BLACK);setColor(y, BLACK);setColor(parentOf(parentOf(x)), RED);x = parentOf(parentOf(x));} else {if (x == leftOf(parentOf(x))) {x = parentOf(x);rotateRight(x);}setColor(parentOf(x), BLACK);setColor(parentOf(parentOf(x)), RED);rotateLeft(parentOf(parentOf(x)));}}}root.color = BLACK;}}

LinkedHashMap

LinkedHashMap:继承自 HashMap,在 HashMap 基础上,通过维护一个具有双重链表解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题。另外LinkedHashMap可以实现快速的查询第一个元素(First)跟结尾(Last)

对于LinkedHashMap详解,可参考如下文章:java之LinkedHashMap详解_linkedhashmap使用_三木易不爱卷的博客-CSDN博客

相关文章:

JAVA集合之Map >>HashMap/Hashtable/TreeMap/LinkedHashMap结构

Map 是一种键-值对&#xff08;key-value&#xff09;集合&#xff0c;键不可以重复&#xff0c;值可以重复。常见的实现类有&#xff1a;HashMap、Hashtable、TreeMap、LinkedHashMap等。 HashMap&Hashtable HashMap&#xff1a;数据结构为哈希表&#xff0c;允许使用 n…...

JavaScript从零开始 学习记录(一)

前言 选择视频课程之前&#xff0c;不仅查阅了资料&#xff0c;还询问了网友&#xff0c;最终敲定了学习黑马前端的视频教程&#xff0c;学了5小节&#xff0c;发现挺对自己口味的且从反响来看&#xff0c;还是相当不错的&#xff0c;便打算利用这个寒假学完 笔记范围 从这节…...

C++项目——高并发内存池(3)--central cache整体设计

1.central cache的介绍 1.1框架思想 1.1.1哈希映射 centralcache其实也是哈希桶结构的&#xff0c;并且central cache和thread cacha的哈希映射关系是一致的。目的为了&#xff0c;当thread cache某一个哈希桶下没有内存块时&#xff0c;可以利用之前编写的SizeClass::Index…...

Spring Boot 整合 MyBatis 配置等案例教程

运行环境&#xff1a;JDK 7 或 8、Maven 3.0 技术栈&#xff1a;SpringBoot 1.5、SpringBoot Mybatis Starter 1.2 、MyBatis 3.4 前言 距离第一篇 Spring Boot 系列的博文 3 个月了。《Springboot 整合 Mybatis 的完整 Web 案例》第一篇出来是 XML 配置 SQL 的形式。虽然 XM…...

比特数据结构与算法(第三章_下)队列的概念和实现(力扣:225+232+622)

一、队列&#xff08;Queue&#xff09;队列的概念&#xff1a;① 队列只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。② 入队列&#xff0c;进行插入操作的一端称为 队尾。出队列&#xff0c;进行删除操作的一端称为 队头。③ 队列中的元素…...

c++提高篇——STL容器实现打分系统

一、案例说明 有5名选手:选手ABCDE&#xff0c;10个评委分别对每一名选手打分&#xff0c;去除最高分&#xff0c;去除评委中最低分&#xff0c;取平均分。 二、案例实现 在实现这个系统时&#xff0c;我们规划一下实现的步骤以及细节&#xff1a; 1、创建一个选手类&#x…...

【图片上传记录三】element-ui组件详解与封装(自定义上传、限制文件大小、格式以及图片尺寸)

业务上有需求是前端上传 jpg/png/gif 格式, 并且 尺寸为 150px * 150px,300px*300px,428*428px 的图片 同时在上传的同时需要携带用户的个人信息以及其他额外信息 因此在 element-upload 基础之上 实现这个需求需要在上传前检查图片的大小&#xff0c;格式以及尺寸如何上传也成…...

一个golang版本管理工具

GitHub - moqsien/gvc: GVC is a productive tool to manage your dev environment for multi platforms and machines. | GVC 是一个用于快速配置和管理多机器跨平台的开发环境的生产力工具。 目前&#xff0c;gvc拥有以下功能或特点&#xff1a; go编译器自动安装和添加环…...

SpringBoot整合Spring Security过滤器链加载执行流程源码分析

文章目录1.引言2.Spring Security过滤器链加载1.2.注册名为 springSecurityFilterChain的过滤器2、查看 DelegatingFilterProxy类3.查看 FilterChainProxy类3.1 查看 doFilterInternal方法。3.2 查看 getFilters方法。4 查看 SecurityFilterChain接口5 查看 SpringBootWebSecur…...

Jest使用

一、测试到底测什么 提到测试的时候&#xff0c;即使是最简单的一个代码块可能都让初学者不知所措。最常问的问题的是“我怎么知道要测试什么&#xff1f;”。如果你正在写一个 Web 应用&#xff0c;那么你每个页面每个页面的测试用户交互的方式&#xff0c;就是一个很好的开端…...

定位于企业数字化底座,开箱可用(spring cloud+Vue)基础框架,赶紧收藏!

项目介绍&#xff1a;JVS是什么&#xff1f;JVS是企业级应用构建的基础脚手架&#xff0c;提供开箱即用的基础功能集成&#xff0c;其中集成了账户管理、租户管理、用户权限体系、三方登录、环境配置、各种业务日志等功能&#xff0c;还提供了对接低代码、数据中台的能力。JVS能…...

java字符统计

问题描述 给定一个只包含大写字母的字符串 &#xfffd; S, 请你输出其中出现次数最多的字符。 如果有多个字母均出现了最多次, 按字母表顺序依次输出所有这些字母。 输入格式 一个只包含大写字母的字符串 &#xfffd; S. 输出格式 若干个大写字母&#xff0c;代表答案。 …...

C#:Krypton控件使用方法详解(第八讲) ——kryptonBreadCrumb

今天介绍的Krypton控件中的kryptonBreadCrumb&#xff0c;下面开始介绍这个控件的属性&#xff1a;首先要介绍的是RootItem属性和外观属性&#xff1a;RootItem属性组中包含属性如下&#xff1a;image属性&#xff1a;代表在文字对象的前方插入一个图片&#xff0c;属性值如下图…...

2023从0开始学性能(1) —— 性能测试基础【持续更新】

背景 不知道各位大佬有没遇到上面的情况&#xff0c;性能这个东西到底是什么&#xff0c;还是以前的358原则吗&#xff1f;明显并不是适用于现在了。多次想踏入性能测试门槛都以失败告终&#xff0c;这次就以系列的方式来督促自己真正踏进性能测试的门槛。 什么是性能测试 通…...

如何通过一台 iPhone 申请一个 icloud 邮箱账号 后缀为 @icloud.com

总目录 iOS开发笔记目录 从一无所知到入门 文章目录需求关键步骤步骤后续需求 在 iPhone 自带的邮箱软件中添加账号&#xff0c;排第一位的是 iCloud 邮箱&#xff1a; 选 iCloud 之后&#xff1a; 提示信息是exampleicloud.com&#xff0c;也就是说是有icloud.com为域的邮箱…...

SQL89 计算总和

描述OrderItems表代表订单信息&#xff0c;包括字段&#xff1a;订单号order_num和item_price商品售出价格、quantity商品数量。order_numitem_pricequantitya110105a211100a21200a421121a5510a2119a775【问题】编写 SQL 语句&#xff0c;根据订单号聚合&#xff0c;返回订单总…...

Netty高级应用之:编解码器与群聊天室开发

Netty高级应用之&#xff1a;编解码器与群聊天室开发 文章目录Netty高级应用之&#xff1a;编解码器与群聊天室开发Netty编解码器Java的编解码Netty编解码器概念解码器(Decoder)编码器(Encoder)编码解码器CodecNetty案例-群聊天室聊天室服务端编写聊天室客户端编写Netty编解码器…...

Vue的生命周期

Vue的生命周期是指Vue实例从创建到销毁的过程&#xff0c;它包括了以下几个阶段&#xff1a;初始化、编译、挂载、更新、渲染和销毁。 初始化&#xff1a;Vue实例创建时&#xff0c;会执行初始化过程&#xff0c;主要包括以下几个步骤&#xff1a; 初始化数据&#xff1a;Vue…...

MySQL —— 数据库基础

文章目录1. centos7 安装Mysql2. 数据库的概念3. 数据库下创建库&#xff0c;表4. 库&#xff0c;表 的本质5. 数据库服务器 和 库 &#xff0c;表的关系6. MySQL架构7. 存储引擎前言&#xff1a; 数据库是对数据进行管理的软件。1. centos7 安装Mysql 需要把系统自带的MySQL给…...

多线程知识点

多线程 基本知识 创建线程的常用三种方式&#xff1a; 继承Thread类实现Runnable接口实现Callable接口&#xff08;JDK1.5>&#xff09; public class ThreadTest extends Thread {Overridepublic void run() {System.out.println(this.getName() "..开始.."…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...