线程面试题-2

news2024/10/7 20:27:30

1、一般用什么作为HashMap的key?

一般用Integer、String 这种不可变类当 HashMap 当 key,而且 String 最为常用。

  • 因为字符串是不可变的,所以在它创建的时候 hashcode 就被缓存了,不需要重新计算。这就是HashMap 中的键往往都使用字符串的原因。

  • 因为获取对象的时候要用到 equals() 和 hashCode() 方法,那么键对象正确的重写这两个方法是非常重要的,这些类已经很规范的重写了 hashCode() 以及 equals() 方法。

2、HashMap为什么线程不安全?

在这里插入图片描述

  • 多线程下扩容死循环。JDK1.7中的 HashMap 使用头插法插入元素,在多线程的环境下,扩容的时候有可能导致环形链表的出现,形成死循环。因此,JDK1.8使用尾插法插入元素,在扩容时会保持链表元素原本的顺序,不会出现环形链表的问题。

  • 多线程的put可能导致元素的丢失。多线程同时执行 put 操作,如果计算出来的索引位置是相同的,那会造成前一个 key 被后一个 key 覆盖,从而导致元素的丢失。此问题在JDK 1.7和 JDK 1.8 中都存在。

  • put和get并发时,可能导致get为null。线程1执行put时,因为元素个数超出threshold而导致rehash,线程2此时执行get,有可能导致这个问题。此问题在JDK 1.7和 JDK 1.8 中都存在。

3、ConcurrentHashMap 的实现原理是什么?

ConcurrentHashMap 在 JDK1.7 和 JDK1.8 的实现方式是不同的。

先来看下JDK1.7

JDK1.7中的ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成,即ConcurrentHashMap 把哈希桶切分成小数组(Segment),每个小数组有 n 个 HashEntry 组成。

其中,Segment 继承了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色;HashEntry用于存储键值对数据。

在这里插入图片描述

首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问,能够实现真正的并发访问。

再来看下JDK1.8

在数据结构上, JDK1.8 中的ConcurrentHashMap 选择了与 HashMap 相同的数组+链表+红黑树结构;在锁的实现上,抛弃了原有的 Segment 分段锁,采用 CAS + synchronized 实现更加低粒度的锁。

将锁的级别控制在了更细粒度的哈希桶元素级别,也就是说只需要锁住这个链表头结点(红黑树的根节点),就不会影响其他的哈希桶元素的读写,大大提高了并发度。

在这里插入图片描述

4、ConcurrentHashMap 的 put 方法执行逻辑是什么?

先来看JDK1.7

首先,会尝试获取锁,如果获取失败,利用自旋获取锁;如果自旋重试的次数超过 64 次,则改为阻塞获取锁。

获取到锁后:

  1. 将当前 Segment 中的 table 通过 key 的 hashcode 定位到 HashEntry。

  2. 遍历该 HashEntry,如果不为空则判断传入的 key 和当前遍历的 key 是否相等,相等则覆盖旧的value。

  3. 不为空则需要新建一个 HashEntry 并加入到 Segment 中,同时会先判断是否需要扩容。

  4. 释放 Segment 的锁。

再来看JDK1.8

大致可以分为以下步骤:

  1. 根据 key 计算出 hash值。

  2. 判断是否需要进行初始化。

  3. 定位到 Node,拿到首节点 f,判断首节点 f:

  • 如果为 null ,则通过cas的方式尝试添加。

  • 如果为 f.hash = MOVED = -1 ,说明其他线程在扩容,参与一起扩容。

  • 如果都不满足 ,synchronized 锁住 f 节点,判断是链表还是红黑树,遍历插入。

  1. 当在链表长度达到8的时候,数组扩容或者将链表转换为红黑树。

5、ConcurrentHashMap 的 get 方法是否要加锁,为什么?

get 方法不需要加锁。因为 Node 的元素 val 和指针 next 是用 volatile 修饰的,在多线程环境下线程A修改结点的val或者新增节点的时候是对线程B可见的。

这也是它比其他并发集合比如 Hashtable、用Collections.synchronizedMap()包装的 HashMap 安全效率高的原因之一。

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    //可以看到这些都用了volatile修饰
    volatile V val;
    volatile Node<K,V> next;
}

6、get方法不需要加锁与volatile修饰的哈希桶有关吗?

没有关系。哈希桶 table 用volatile修饰主要是保证在数组扩容的时候保证可见性。

static final class Segment<K,V> extends ReentrantLock implements Serializable {
    // 存放数据的桶
    transient volatile HashEntry<K,V>[] table;
}

7、ConcurrentHashMap 不支持 key 或者 value 为null 的原因?

我们先来说value 为什么不能为 null ,因为 ConcurrentHashMap 是用于多线程的 ,如果map.get(key) 得到了 null ,无法判断,是映射的value是 null ,还是没有找到对应的key而为 null ,这就有了二义性。

而用于单线程状态的 HashMap 却可以用 containsKey(key) 去判断到底是否包含了这个 null 。

我们用反证法来推理:

假设ConcurrentHashMap 允许存放值为 null 的value,这时有A、B两个线程,线程A调用ConcurrentHashMap .get(key)方法,返回为 null ,我们不知道这个 null 是没有映射的 null ,还是存的值就是 null 。

假设此时,返回为 null 的真实情况是没有找到对应的key。那么,我们可以用ConcurrentHashMap.containsKey(key)来验证我们的假设是否成立,我们期望的结果是返回false。

但是在我们调用ConcurrentHashMap .get(key)方法之后,containsKey方法之前,线程B执行了ConcurrentHashMap .put(key, null )的操作。那么我们调用containsKey方法返回的就是true了,这就与我们的假设的真实情况不符合了,这就有了二义性。

8、ConcurrentHashMap 的并发度是多少?

在JDK1.7中,并发度默认是16,这个值可以在构造函数中设置。如果自己设置了并发度,ConcurrentHashMap 会使用大于等于该值的最小的2的幂指数作为实际并发度,也就是比如你设置的值是17,那么实际并发度是32。

9、ConcurrentHashMap 迭代器是强一致性还是弱一致性?

与HashMap迭代器是强一致性不同,ConcurrentHashMap 迭代器是弱一致性。

ConcurrentHashMap 的迭代器创建后,就会按照哈希表结构遍历每个元素,但在遍历过程中,内部元素可能会发生变化,如果变化发生在已遍历过的部分,迭代器就不会反映出来,而如果变化发生在未遍历过的部分,迭代器就会发现并反映出来,这就是弱一致性。

这样迭代器线程可以使用原来老的数据,而写线程也可以并发的完成改变,更重要的,这保证了多个线程并发执行的连续性和扩展性,是性能提升的关键。

10、JDK1.7与JDK1.8 中ConcurrentHashMap 的区别?

  • 数据结构:取消了Segment分段锁的数据结构,取而代之的是数组+链表+红黑树的结构。

  • 保证线程安全机制:JDK1.7采用Segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock。JDK1.8 采用CAS+Synchronized保证线程安全。

  • 锁的粒度:原来是对需要进行数据操作的Segment加锁,现调整为对每个数组元素加锁(Node)。

  • 链表转化为红黑树:定位结点的hash算法简化会带来弊端,Hash冲突加剧,因此在链表节点数量大于8时,会将链表转化为红黑树进行存储。

  • 查询时间复杂度:从原来的遍历链表O(n),变成遍历红黑树O(logN)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/915932.html

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

相关文章

【vue3】vite工具创建vue3项目,遇到的坑及解决办法

1、在对应文件夹下执行npm create vite 报错如下&#xff1a; 解决步骤可看这篇文章&#xff1a;npm install报错 -&#xff1e; npm ERR! Unexpected token ‘.‘ 报错解决办法 主要是因为我的nvm版本是1.1.7&#xff0c;版本太低&#xff0c;里面没有集成高版本node导致的 将…

基于swing的超市信息管理系统java jsp仓库进销存mysql源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于swing的超市信息管理系统 系统有1权限&#xff1…

〔016〕Stable Diffusion 之 模型工具箱和图片背景移除 篇

✨ 目录 🎈 下载插件🎈 基础使用界面🎈 高级使用界面🎈 下载背景移除插件🎈 移除插件使用🎈 下载插件 由于模型很多,而且底模也非常大,对于空间占用比较大,如果想缩小模型体积,可以使用模型工具箱插件该插件主要支持 模型的修剪、转换.safetensors格式、提取和…

Java“牵手”虾皮商品详情数据,根据商品ID获取虾皮(Shopee商品详情数据接口,虾皮API接口申请指南

虾皮&#xff08;shopee&#xff09;商城是一个跨境网上批发购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取虾皮商品详情数据&#xff0c;您可以通过开放平台的接口或者直接访问虾皮商城的网页来获取商品详情信息。以下…

vue 简单实验 数据更新

1.代码 <script src"https://unpkg.com/vuenext" rel"external nofollow" ></script> <div id"counter">Counter: {{ counter }} </div> <script> const Counter {data() {return {counter: 5}},mounted() {set…

从陌生到熟练使用string类

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f…

基于nginx禁用访问ip

一、背景 网络安全防护时&#xff0c;禁用部分访问ip,基于nginx可快速简单实现禁用。 二、操作 1、创建 conf.d文件夹 在nginx conf 目录下创建conf.d文件夹 Nginx 扩展配置文件一般在conf.d mkdir conf.d 2、新建blocksip.conf文件 在conf.d目录新建禁用ip的扩展配置文…

关于LED电子显示屏幕的显示功能

因为LED显示屏的发光颜色和发光效率与制作LED的材料和工艺相关&#xff0c;目前广泛采用的有红、绿、蓝三种颜色的LED。这些LED的独特之处在于它们工作时需要的电压极低&#xff08;仅1.5-3V&#xff09;&#xff0c;能够主动发光&#xff0c;并且具有一定的亮度。这亮度可以通…

清醒和非快速眼动睡眠EEG微状态序列的频率分析

摘要 大多数脑电(EEG)微状态分析都是在清醒状态下进行数据采集&#xff0c;而现有的睡眠研究主要集中在空间微状态特性的变化以及相邻时间点之间的微状态转换上&#xff0c;睡眠状态下脑电微状态研究尚且不足。本研究旨在对清醒和非快速眼动(NREM)睡眠阶段的非平滑EEG微状态序…

Swift 周报 第三十四期

文章目录 前言新闻和社区iPhone Pro 要提价&#xff01;新款 iPhone 或会使用 USB-C 充电器&#xff0c;边框更薄与 App Store 专家会面交流让你的 App 和游戏在 visionOS 模拟器外更进一步 提案通过的提案正在审查的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swif…

AutoSAR配置与实践(基础篇)3.4 BSW 的存储功能

AutoSAR配置与实践(基础篇)3.4 BSW 的存储功能 一、存储功能简介二、片内存储三、片外存储一、存储功能简介 分层和模块: 在内存栈中包含服务层(NvM)、抽象层(MemIf、EA、Fee、Ex EE Drv、Ex Fls Drv)、MCAL(SPI、EE Drv、Fls Drv)几个模块。 片内外存储: AutoSAR…

windows下nginx配置为服务

​ 1.下载winswx。 下载地址&#xff1a;winsw下载 2.解压后将其重命名为“nginx-service”,并将其放到nginx目录下。 3.新建一个文本文档内容如下&#xff1a;&#xff08;里面的路径根据自己的情况修改&#xff09; <service> <id>nginx</id> <name&…

内核编译机制

inux内核的编译主要过程&#xff1a;配置、编译、安装。 配置主要由Kconfig提供图形界面完成 编译主要基于Kbuild编译系统&#xff0c;执行make完成编译 安装主要也是基于Kbuild提供的脚本&#xff0c;然后执行make完成安装 Kconfig Kconfig用于内核的配置&#xff0c;mak…

PyQt5实操及问题记录

下载与配置 下载 下载使用pip install即可 pip install PyQt5 -i https://pypi.douban.com/simple pip install PyQt5-tools -i https://pypi.douban.com/simple配置 参考&#xff1a; https://blog.csdn.net/m0_57021623/article/details/123459038?ops_request_misc%257…

线程池一定需要了解的那些事

一、阿里Java开发规范&#xff0c;为啥禁止直接使用Executors创建线程池 newFixdThreadPool 及 singleThreadPool 中默认队列长度为 Integer.MAX_VALUE&#xff0c;如果线程执行比较耗时&#xff0c;执行任务的线程在队列中产生大量堆积&#xff0c;进而有导致虚拟机OOM 的风险…

罗德与施瓦茨网络分析仪RSZVA40

ZVA40 主要特点 台具有以下特点的矢量网络分析仪 带 4 个内部信号源&#xff0c;频率高达 67 GHz&#xff0c;可以快速地对放大器和混频器进行测量 具有 4 个相位相干信号发生器功能&#xff08;频率可高达 67 GHz&#xff09; 壹捌叁贰零玖壹捌陆伍叁 中频带宽可高达 30 …

2023国赛数学建模思路 - 案例:最短时间生产计划安排

文章目录 0 赛题思路1 模型描述2 实例2.1 问题描述2.2 数学模型2.2.1 模型流程2.2.2 符号约定2.2.3 求解模型 2.3 相关代码2.4 模型求解结果 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 最短时…

一、pikachu之SQL注入(1)

文章目录 一、SQL注入步骤二、数字型注入(post注入)三、字符型注入(get)四、搜索型注入五、XX型注入六、“insert/updata”注入 一、SQL注入步骤 寻找传参页面&#xff1b;判断是否存在注入点&#xff1b; 字符型注入&#xff1f;数字型注入&#xff1f; 判断字段的数量&#…

引领娱乐潮流:邀请明星办个人演唱会的五大关键步骤

随着娱乐产业的不断壮大和观众对明星的热情高涨&#xff0c;举办个人演唱会已经成为了一种广受欢迎的文化现象。这种活动不仅让粉丝们有机会亲身近距离感受偶像的音乐魅力&#xff0c;同时也为明星和品牌提供了一个宝贵的互动平台。然而&#xff0c;要成功地邀请明星办个人演唱…

Prometheus监控之SNMP Exporter介绍和数据展现

1 SNMP协议介绍 SNMP协议全称是&#xff1a;Simple Network Management Protocol&#xff0c;译为简单网络管理协议&#xff0c;是作为TCP/IP网络管理标准协议&#xff0c;为不同的设备提供统一接口&#xff0c;实现了网络设备之间的统一管理。 SNMP协议分为三个版本&#xf…