线程面试题-1

news2024/11/22 23:49:27

看的博客里面总结的线程的八股文

1、线程安全的集合有哪些?线程不安全的呢?

线程安全的:

  • Hashtable:比HashMap多了个线程安全。

  • ConcurrentHashMap:是一种高效但是线程安全的集合。

  • Vector:比Arraylist多了个同步化机制。

  • Stack:栈,也是线程安全的,继承于Vector。

线性不安全的:

  • HashMap

  • Arraylist

  • LinkedList

  • HashSet

  • TreeSet

  • TreeMap

2、Arraylist与 LinkedList 异同点?

  • 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;

  • 底层数据结构: Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向循环链表数据结构;

  • 插入和删除是否受元素位置的影响: ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行 add(E e) 方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话( add(int index, E element) )时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是近似 O(1)而数组为近似 O(n)。

  • 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而ArrayList 实现了RandmoAccess 接口,所以有随机访问功能。快速随机访问就是通过元素的序号快速获取元素对象(对应于 get(int index) 方法)。

  • 内存空间占用: ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。

3、ArrayList 与 Vector 区别?

  • Vector是线程安全的,ArrayList不是线程安全的。其中,Vector在关键性的方法前面都加了synchronized关键字,来保证线程的安全性。如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码。

  • ArrayList在底层数组不够用时在原来的基础上扩展0.5倍,Vector是扩展1倍,这样ArrayList就有利于节约内存空间。

4、说一说ArrayList 的扩容机制?

ArrayList扩容的本质就是计算出新的扩容数组的size后实例化,并将原有数组内容复制到新数组中去。

默认情况下,新的容量会是原容量的1.5倍

以JDK1.8为例说明:

public boolean add(E e) {
    //判断是否可以容纳e,若能,则直接添加在末尾;若不能,则进行扩容,然后再把e添加在末尾
    ensureCapacityInternal(size + 1); // Increments modCount!!
    //将e添加到数组末尾
    elementData[size++] = e;
    return true;
    }
/* 每次在add()一个元素时,arraylist都需要对这个list的容量进行一个判断。通过
ensureCapacityInternal()方法确保当前ArrayList维护的数组具有存储新元素的能力,经过处理之后
将元素存储在数组elementData的尾部*/
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//如果传入的是个空数组则最小容量取默认容量与minCapacity之间的最大值
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
/* 若ArrayList已有的存储能力满足最低存储要求,则返回add直接添加元素;如果最低要求的
存储能力>ArrayList已有的存储能力,这就表示ArrayList的存储能力不足,因此需要调用 grow();方法
进行扩容*/
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // 获取elementData数组的内存空间长度
    int oldCapacity = elementData.length;
    // 扩容至原来的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //校验容量是否够
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    //若预设值大于默认的最大值,检查是否溢出
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // 调用Arrays.copyOf方法将elementData数组指向新的内存空间
    //并将elementData的数据复制到新的内存空间
    elementData = Arrays.copyOf(elementData, newCapacity);
}

5、Array 和 ArrayList 有什么区别?什么时候该应 Array而不是 ArrayList 呢?

  • Array 可以包含基本类型和对象类型,ArrayList 只能包含对象类型。

  • Array 大小是固定的,ArrayList 的大小是动态变化的。

  • ArrayList 提供了更多的方法和特性,比如:addAll(),removeAll(),iterator() 等等。

6、HashMap的底层数据结构是什么?

在JDK1.7 和JDK1.8 中有所差别:

在JDK1.7 中,由“数组+链表”组成,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。

在JDK1.8 中,由“数组+链表+红黑树”组成。当链表过长,则会严重影响 HashMap 的性能,红黑树搜索时间复杂度是 O(logn),而链表是糟糕的 O(n)。因此,JDK1.8 对数据结构做了进一步的优化,引入了红黑树,链表和红黑树在达到一定条件会进行转换:

  • 当链表超过 8 且数据总量超过 64 才会转红黑树。

  • 将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树,以减少搜索时间。

在这里插入图片描述

7、解决hash冲突的办法有哪些?HashMap用的哪种?

解决Hash冲突方法有:开放定址法、再哈希法、链地址法(拉链法)、建立公共溢出区。HashMap中采用的是 链地址法

  • 开放定址法也称为 再散列法 ,基本思想就是,如果 p=H(key) 出现冲突时,则以 p 为基础,再次hash, p1=H§ ,如果p1再次出现冲突,则以p1为基础,以此类推,直到找到一个不冲突的哈希地址 pi 。 因此开放定址法所需要的hash表的长度要大于等于所需要存放的元素,而且因为存在再次hash,所以 只能在删除的节点上做标记,而不能真正删除节点。

  • 再哈希法(双重散列,多重散列),提供多个不同的hash函数,当 R1=H1(key1) 发生冲突时,再计算 R2=H2(key1) ,直到没有冲突为止。 这样做虽然不易产生堆集,但增加了计算的时间。

  • 链地址法(拉链法),将哈希值相同的元素构成一个同义词的单链表,并将单链表的头指针存放在哈希表的第i个单元中,查找、插入和删除主要在同义词链表中进行。链表法适用于经常进行插入和删除的情况。

  • 建立公共溢出区,将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区。

8、为什么在解决 hash 冲突的时候,不直接用红黑树?而选择先用链表,再转红黑树?

因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡,而单链表不需要。当元素小于 8 个的时候,此时做查询操作,链表结构已经能保证查询性能。当元素大于 8 个的时候, 红黑树搜索时间复杂度是 O(logn),而链表是 O(n),此时需要红黑树来加快查询速度,但是新增节点的效率变慢了。

因此,如果一开始就用红黑树结构,元素太少,新增效率又比较慢,无疑这是浪费性能的。

9、HashMap默认加载因子是多少?为什么是 0.75,不是0.6 或者 0.8 ?

回答这个问题前,我们来先看下HashMap的默认构造函数:

int threshold; // 容纳键值对的最大值
final float loadFactor; // 负载因子
int modCount;
int size;

Node[] table的初始化长度length(默认值是16),Load factor为负载因子(默认值是0.75),threshold是HashMap所能容纳键值对的最大值。threshold = length * Load factor。也就是说,在数组定义好长度之后,负载因子越大,所能容纳的键值对个数越多。

默认的loadFactor是0.75,0.75是对空间和时间效率的一个平衡选择,一般不要修改,除非在时间和空间比较特殊的情况下 :

  • 如果内存空间很多而又对时间效率要求很高,可以降低负载因子Load factor的值 。

  • 相反,如果内存空间紧张而对时间效率要求不高,可以增加负载因子loadFactor的值,这个值可以大于1。

追溯下作者在源码中的注释(JDK1.7):

As a general rule, the default load factor (.75) offers a good tradeoff between
time and space costs. Higher values decrease the space overhead but increase the
lookup cost (reflected in most of the operations of the HashMap class, including
get and put). The expected number of entries in the map and its load factor
should be taken into account when setting its initial capacity, so as to
minimize the number of rehash operations. If the initial capacity is greater
than the maximum number of entries divided by the load factor, no rehash
operations will ever occur.

翻译过来大概的意思是:作为一般规则,默认负载因子(0.75)在时间和空间成本上提供了很好的折衷。较高的值会降低空间开销,但提高查找成本(体现在大多数的HashMap类的操作,包括get和put)。设置初始大小时,应该考虑预计的entry数在map及其负载系数,并且尽量减少rehash操作的次数。如果初始容量大于最大条目数除以负载因子,rehash操作将不会发生。

10、HashMap 的put方法流程?

以JDK1.8为例,简要流程如下:

  1. 首先根据 key 的值计算 hash 值,找到该元素在数组中存储的下标;

  2. 如果数组是空的,则调用 resize 进行初始化;

  3. 如果没有哈希冲突直接放在对应的数组下标里;

  4. 如果冲突了,且 key 已经存在,就覆盖掉 value;

  5. 如果冲突后,发现该节点是红黑树,就将这个节点挂在树上;

  6. 如果冲突后是链表,判断该链表是否大于 8 ,如果大于 8 并且数组容量小于 64,就进行扩容;如果链表节点大于 8 并且数组的容量大于 64,则将这个结构转换为红黑树;否则,链表插入键值对,若 key 存在,就覆盖掉 value。

在这里插入图片描述

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

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

相关文章

Ubuntu本地快速搭建web小游戏网站,并使用内网穿透将其发布到公网上

文章目录 前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar内网穿透3.2 创建隧道3.3 测试公网访问 4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子域名 前言 网&#xff1a;我们通常说的是互联网&am…

SpringBoot中乐观锁的实现 (精简demo)

使用场景: 当要更新一条数据时&#xff0c;希望这条数据没有被别人更新&#xff0c;也就是说实现线程安全的数据更新 1. 数据库新增version字段, int类型, 默认值为0 2. 引入依赖 <!--mybatis拦截器--> <dependency><groupId>com.baomidou</groupId>&…

Nginx使用keepalived配置VIP

VIP常用于负载均衡的高可用&#xff0c;使用VIP可以给多个主机绑定一个IP&#xff0c;这样&#xff0c;当某个负载应用挂了之后&#xff0c;可以自动切到另一个负载。 我这里是在k8s环境中做的测试&#xff0c;集群中有6个节点&#xff0c;我给140和141两个节点配置VIP。 1. 安…

【leetcode 力扣刷题】移除链表元素 多种解法

移除链表元素的多种解法 203. 移除链表元素解法①&#xff1a;头节点单独判断解法②&#xff1a;虚拟头节点解法③&#xff1a;递归 203. 移除链表元素 题目链接&#xff1a;203.移除链表元素 题目内容&#xff1a; 理解题意&#xff1a;就是单纯的删除链表中所有值等于给定的…

Java【HTTP】什么是 Cookie 和 Session? 如何理解这两种机制的区别和作用?

文章目录 前言一、Cookie1, 什么是 Cookie2, Cookie 从哪里来3, Cookie 到哪里去4, Cookie 有什么用 二、Session1, 什么是 Session2, 理解 Session 三、Cookie 和 Session 的区别总结 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; …

并查集 size 的优化(并查集 size 的优化)

目录 并查集 size 的优化 Java 实例代码 UnionFind3.java 文件代码&#xff1a; 并查集 size 的优化 按照上一小节的思路&#xff0c;我们把如下图所示的并查集&#xff0c;进行 union(4,9) 操作。 合并操作后的结构为&#xff1a; 可以发现&#xff0c;这个结构的树的层相对…

juc概述和Lock接口

目录 一、什么是JUC 1、JUC概述 2、进程与线程 3、线程的状态 4、wait/sleep 的区别 5、并发与并行 6、管程 7、用户线程和守护线程 二、Lock接口 1、Synchronized 使用synchronized实现售票案例 使用synchronized实现增减变量操作 2、什么是 Lock 买票例子使用lo…

如何选择 DCDC 降压型开关电源的电感

选择合适的电感是开关电源电路设计的关键之一。本文将帮助您理解电感值和电路性能之间的关系。 降压转换器&#xff08;buck converter&#xff09;&#xff0c;也称为降压转换器(step-down converter)&#xff0c;是一种开关模式稳压器&#xff08;voltage regulator&#xf…

Mac常见恶意软件再现,办公应用程序潜藏风险如何防范?

Mac电脑正受到臭名昭著的XLoader恶意软件的新变种的攻击&#xff0c;该恶意软件已被重写为在最好的MacBook上本地运行。 虽然XLoader至少从2015年开始出现&#xff0c;但在2021年发现macOS变体之前&#xff0c;它主要用于针对Windows PC。然而&#xff0c;该版本是作为Java程序…

win10系统rust串口通信实现

一、用cargo创建新工程 命令&#xff1a;cargo new comport use std::env; use std::{thread, time}; use serialport::{DataBits, StopBits, Parity, FlowControl}; use std::io::{self, Read, Write}; use std::time::Duration;fn main() -> io::Result<()> {let m…

CSS中的display属性有哪些值?它们的作用?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ CSS display 属性的不同取值和作用1. block2. inline3. inline-block4. none5. flex6. grid7. table、table-row、table-cell8. list-item9. inline-table、table-caption、table-column 等 ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#x…

Pika Labs - 用AI工具生成短视频大片

今天我要跟大家分享如何用AI工具1分钟内生成一个短视频大片&#xff0c;效果完全不输影视大V。 只需要用一句话就可以生成视频&#xff0c;或者用一张图就能生成视频&#xff0c;这就是最新推出的AI工具Pika Labs&#xff01;被网友誉为“全球最优秀的文本生成视频AI”。 目前…

SharedPreferences详解及其ANR解决方案

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、使用四、原理五、存在的问题六、优…

Android动态添加和删除控件/布局

一、引言 最近在研究RecyclerView二级列表的使用方法&#xff0c;需要实现的效果如下。 然后查了一些博客&#xff0c;觉得实现方式太过复杂&#xff0c;而且这种方式也不是特别受推荐&#xff0c;所以请教了别人&#xff0c;得到了一种感觉还不错的实现方式。实现的思路为&…

【LeetCode-经典面试150题-day9]

目录 36.有效的数独 54.螺旋矩阵 48.旋转图像 73.矩阵置零 36.有效的数独 题意&#xff1a; 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1…

huggingface datasets离线加载文件的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Sim/circuit10

通过观察可知&#xff0c;在a、b同时为0或1时&#xff0c;state的值改变 state的值可以改变q的输出&#xff0c;1为ab的同或&#xff0c;0为异或 利用assign q进行输出 module top_module (input clk,input a,input b,output q,output state );always(posedge clk)if(a&…

【TypeScript】元组

元组&#xff08;Tuple&#xff09;是 TypeScript 中的一种特殊数据类型&#xff0c;它允许你定义一个固定数量和类型的元素组合。元组可以包含不同类型的数据&#xff0c;每个数据的类型在元组中都是固定的。以下是 TypeScript 中元组的基本用法和特点&#xff1a; // 声明一…

Win系统下安装Linux双系统教程

软件下载 软件&#xff1a;Linux版本&#xff1a;18.0.4语言&#xff1a;简体中文大小&#xff1a;1.82G安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.0GHz 内存4G(或更高&#xff09;下载通道①丨百度网盘&#xff1a;1.ubuntu18.0.4下载链接&#xf…

量子计算对信息安全的影响:探讨量子计算技术对现有加密方法和信息安全基础设施可能带来的颠覆性影响,以及应对策略

第一章&#xff1a;引言 随着科技的迅猛发展&#xff0c;量子计算作为一项颠覆性的技术正逐渐走入我们的视野。量子计算以其强大的计算能力引发了全球科技界的广泛关注。然而&#xff0c;正如硬币的两面&#xff0c;量子计算技术所带来的不仅仅是计算能力的巨大飞跃&#xff0…