当前位置: 首页> 财经> 产业 > 文创产品设计ppt_免费的cms有哪些平台_如何优化搜索关键词_怎么自己做个网站

文创产品设计ppt_免费的cms有哪些平台_如何优化搜索关键词_怎么自己做个网站

时间:2025/7/14 23:38:19来源:https://blog.csdn.net/weixin_43999182/article/details/146346363 浏览次数:0次
文创产品设计ppt_免费的cms有哪些平台_如何优化搜索关键词_怎么自己做个网站

1. HashMap扩容

原理:

  • 扩容时机:当HashMap中的元素数量超过 容量(capacity) × 负载因子(load factor,默认0.75) 时,触发扩容。
  • 扩容过程:容量翻倍(从16变为32,以此类推),重新计算每个元素的哈希位置(rehash),将原有元素迁移到新数组。

具体步骤:

1.检查阈值:

  • 初始容量默认16,负载因子0.75,阈值(threshold)= 16 × 0.75 = 12。
  • 放入第13个元素时触发扩容。

2.新数组分配:

  • 新容量 = 旧容量 × 2(如16 -> 32)。
  • 创建新数组,长度为新容量。

3.元素迁移(rehash):

  • JDK 1.7:遍历所有链表,重新计算每个元素的哈希位置,复杂度O(n)。
  • JDK 1.8:优化为利用位运算,分为高位和低位链表,提高效率。
    • 原索引位置 = hash & (oldCap - 1)。
    • 新索引位置 = 原索引 或 原索引 + oldCap(取决于hash的高位bit)。

代码关键点(JDK 1.8):

void resize() {// 计算新容量和新阈值int newCap = oldCap << 1; // 左移1位,容量翻倍int newThr = oldThr << 1; // 阈值翻倍Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];// 迁移元素for (int j = 0; j < oldCap; ++j) {Node<K,V> e = oldTab[j];if (e != null) {if (e.next == null) // 单个节点newTab[e.hash & (newCap - 1)] = e;else if (e instanceof TreeNode) // 红黑树((TreeNode<K,V>)e).split(this, newTab, j, oldCap);else { // 链表Node<K,V> loHead = null, loTail = null; // 低位链表Node<K,V> hiHead = null, hiTail = null; // 高位链表do {if ((e.hash & oldCap) == 0) { // 留在原位置if (loTail == null) loHead = e;else loTail.next = e;loTail = e;} else { // 移到高位(原位置+oldCap)if (hiTail == null) hiHead = e;else hiTail.next = e;hiTail = e;}} while ((e = e.next) != null);if (loTail != null) {loTail.next = null;newTab[j] = loHead;}if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}}}}
}

面试要点:

为什么容量是2的幂?:方便用位运算(&)代替取模(%),提升性能。
1.7 vs 1.8:1.7扩容可能导致链表逆序(多线程死循环问题),1.8优化了迁移逻辑。
负载因子0.75:平衡空间和时间效率,太高冲突多,太低浪费空间。

2. 红黑树转换条件(8和6的阈值)

背景:

JDK 1.8引入红黑树优化HashMap,当链表过长时转为红黑树,提高查询效率(从O(n)到O(log n))。

转换条件:

1.链表转红黑树(Treeify Threshold = 8):

当某个桶的链表长度达到 8,且总容量 ≥ 64时,链表转为红黑树。
如果容量 < 64,只触发扩容,不转红黑树。
源码常量:static final int TREEIFY_THRESHOLD = 8;

2.红黑树转链表(Untreeify Threshold = 6):

当红黑树节点数减少到 6 或以下时,退化为链表。
源码常量:static final int UNTREEIFY_THRESHOLD = 6;

3.为什么是8和6?

统计学依据:泊松分布下,哈希冲突导致链表长度达到8的概率极低(约百万分之一),此时转为红黑树合理。
6和8的间隙:避免频繁转换(链表<->红黑树),增加稳定性。

源码片段:

// put时检查是否转红黑树
if (binCount >= TREEIFY_THRESHOLD - 1) { // binCount从0开始,所以是7时检查treeifyBin(tab, hash);
}// treeifyBin方法
private void treeifyBin(Node<K,V>[] tab, int hash) {int n = tab.length;if (n < MIN_TREEIFY_CAPACITY) // MIN_TREEIFY_CAPACITY = 64resize(); // 容量小于64时扩容else {// 转为红黑树逻辑}
}

面试要点:

容量限制:小于64不转红黑树,避免小容量下频繁转换。
性能权衡:链表适合小数据量,红黑树适合大数据量,8和6是经验值。
扩容影响:扩容后链表可能变短,红黑树可能退化。

3. ThreadLocal内存泄漏案例

ThreadLocal原理:

每个线程有自己的ThreadLocalMap(键是ThreadLocal对象,值是用户设置的值)。
ThreadLocalMap用弱引用存储键,强引用存储值。

内存泄漏场景:

问题:线程长期存活(如线程池中的线程),ThreadLocal对象被GC回收(因弱引用),但对应的值(强引用)未被清理,导致内存泄漏。
案例:

public class ThreadLocalLeakDemo {private static final ThreadLocal<String> tl = new ThreadLocal<>();public static void main(String[] args) {Thread thread = new Thread(() -> {tl.set("Big Object"); // 设置大对象// tl.remove(); // 未调用remove});thread.start();thread.join();// 主线程结束,ThreadLocal对象可能被GC,但"Big Object"仍留在thread的ThreadLocalMap中}
}
  • 如果线程复用(如线程池),ThreadLocalMap不清理,值对象持续占用内存。

泄漏原因:

  • ThreadLocalMap的Entry键是弱引用,ThreadLocal对象被回收后,键变为null,但值仍强引用,导致无法被GC。

解决办法:

  • 手动清理:用完后调用tl.remove()。
try {tl.set("Data");// 使用
} finally {tl.remove(); // 确保清理
}

源码分析:

// ThreadLocalMap的Entry
static class Entry extends WeakReference<ThreadLocal<?>> {Object value; // 强引用Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
}

面试要点:

  • 弱引用作用:防止ThreadLocal对象本身泄漏,但值仍可能滞留。
  • 线程池场景:高危场景,需特别注意remove。
  • 最佳实践:finally块中清理ThreadLocal。

记录建议(面试准备)

1.HashMap扩容:

  • 画图:16->32,链表拆分为高低位。
  • 记公式:threshold = capacity × loadFactor。

2.红黑树转换:

  • 记住:8转树,6转链,容量<64只扩容。
  • 口诀:链表八变树,树六回链表。

3.ThreadLocal内存泄漏:

  • 写demo:线程池+ThreadLocal,未remove vs remove。
  • 记结论:弱引用键+强引用值,未清理=泄漏。
关键字:文创产品设计ppt_免费的cms有哪些平台_如何优化搜索关键词_怎么自己做个网站

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: