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

商城网站建设所必备的四大功能是哪些陕西网站建设公司排名

商城网站建设所必备的四大功能是哪些,陕西网站建设公司排名,设计的网站都有哪些功能,网站怎样做301跳转文章目录 Java集合框架面试题(30道)引言1.说说有哪些常见集合#xff1f; List2.ArrayList和LinkedList有什么区别#xff1f;3.ArrayList的扩容机制了解吗#xff1f;4.ArrayList怎么序列化的知道吗#xff1f;为什么用transient修饰数组#xff1f;5.快速失败#xff0… 文章目录 Java集合框架面试题(30道)引言1.说说有哪些常见集合 List2.ArrayList和LinkedList有什么区别3.ArrayList的扩容机制了解吗4.ArrayList怎么序列化的知道吗为什么用transient修饰数组5.快速失败fail-fast和安全失败fail-safe了解吗6.有哪几种实现ArrayList线程安全的方法7.CopyOnWriteArrayList了解多少 Map8.能说一下HashMap的数据结构吗9.你对红黑树了解多少为什么不用二叉树/平衡树呢10.红黑树怎么保持平衡的知道吗11.HashMap的put流程知道吗12.HashMap怎么查找元素的呢13.HashMap的哈希/扰动函数是怎么设计的14.为什么哈希/扰动函数能降hash碰撞15.为什么HashMap的容量是2的倍数呢16.如果初始化HashMap传一个17的值new HashMap它会怎么处理17.你还知道哪些哈希函数的构造方法呢18.解决哈希冲突有哪些方法呢19.为什么HashMap链表转红黑树的阈值为8呢20.扩容在什么时候呢为什么扩容因子是0.7521.那扩容机制了解吗22.jdk1.8对HashMap主要做了哪些优化呢为什么23.你能自己设计实现一个HashMap吗24.HashMap是线程安全的吗多线程下会有什么问题25.有什么办法能解决HashMap线程不安全的问题呢26.能具体说一下ConcurrentHashmap的实现吗1.7分段锁1.8 CASsynchronized 27.HashMap内部节点是有序的吗28.讲讲LinkedHashMap怎么实现有序的29.讲讲TreeMap怎么实现有序的 Set30.讲讲HashSet的底层实现 Java集合框架面试题(30道) 引言 1.说说有哪些常见集合 集合相关类和接口都在java.util中主要分为3种List列表、Map映射、Set集。 其中 Collection 是集合 List、Set 的父接口它主要有两个子接口 List存储的元素有序可重复。Set存储的元素无序不可重复。 Map是另外的接口是键值对映射结构的集合。 List List也没啥好问的但不排除面试官剑走偏锋比如面试官也看了这个哈哈 2.ArrayList和LinkedList有什么区别 1数据结构不同 ArrayList基于数组实现LinkedList基于双向链表实现 2多数情况下ArrayList更利于查找LinkedList更利于增删 ArrayList基于数组实现get(int index)可以直接通过数组下标获取时间复杂度是O(1)LinkedList基于链表实现get(int index)需要遍历链表时间复杂度是O(n)当然get(E element)这种查找两种集合都需要遍历时间复杂度都是O(n)。ArrayList增删如果是数组末尾的位置直接插入或者删除就可以了但是如果插入中间的位置就需要把插入位置后的元素都向前或者向后移动甚至还有可能触发扩容双向链表的插入和删除只需要改变前驱节点、后继节点和插入节点的指向就行了不需要移动元素。 注意这个地方可能会出陷阱LinkedList更利于增删更多是体现在平均步长上不是体现在时间复杂度上二者增删的时间复杂度都是O(n) 3是否支持随机访问 ArrayList基于数组所以它可以根据下标查找支持随机访问当然它也实现了RandmoAccess接口这个接口只是用来标识是否支持随机访问。LinkedList基于链表所以它没法根据序号直接获取元素它没有实现RandmoAccess接口标记不支持随机访问。 4内存占用ArrayList基于数组是一块连续的内存空间LinkedList基于链表内存空间不连续它们在空间占用上都有一些额外的消耗 ArrayList是预先定义好的数组可能会有空的内存空间存在一定空间浪费LinkedList每个节点需要存储前驱和后继所以每个节点会占用更多的空间 3.ArrayList的扩容机制了解吗 ArrayList是基于数组的集合数组的容量是在定义的时候确定的如果数组满了再插入就会数组溢出。所以在插入时候会先检查是否需要扩容如果当前容量1超过数组长度就会进行扩容。 ArrayList的扩容是创建一个1.5倍的新数组然后把原数组的值拷贝过去。 4.ArrayList怎么序列化的知道吗为什么用transient修饰数组 ArrayList的序列化不太一样它使用transient修饰存储元素的elementData的数组transient关键字的作用是让被修饰的成员属性不被序列化。 为什么最ArrayList不直接序列化元素数组呢 出于效率的考虑数组可能长度100但实际只用了50剩下的50不用其实不用序列化这样可以提高序列化和反序列化的效率还可以节省内存空间。 那ArrayList怎么序列化呢 ArrayList通过两个方法readObjectwriteObject自定义序列化和反序列化策略实际直接使用两个流ObjectOutputStream和ObjectInputStream来进行序列化和反序列化。 /** * 自定义序列化 */ private void writeObject(java.io.ObjectoutputStream s) throws java.io.IOException{//fail-fast,后续判断是否有并发处理int expectedModCount modCount;//序列化没有标记为 static、transient 的字段,包括 size 等.s.defaultwriteObject();s.writeInt(size);//序列化数组的前size个元素for(int i0; i size; i){s.writeObject(elementData[i]);}if(modCount ! expectedModCount){throw new ConcurrentModificationException();} }/* * 自定义反序列化 */ private void readobject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {elementData EMPTY_ELEMENTDATA;//反序列化没有标记为 static、transient 的字段,包括 size 等s.defaultReadobject();s.readInt();//ignored if(size 0){//数组扩容int capacity calculateCapacity(elementData, size);SharedSecrets.getJavaOISAccess().checkArray(s,Object[].class,capacity);ensureCapacityInternal(size);Object[]a elementData;//反序列化元素并填充到数组中for(int i0;isize;i){a[i] s.readObject();}} }5.快速失败fail-fast和安全失败fail-safe了解吗 快速失败fail—fast快速失败是Java集合的一种错误检测机制 在用迭代器遍历一个集合对象时如果线程A遍历过程中线程B对集合对象的内容进行了修改增加、删除、修改则会抛出Concurrent Modification Exception。原理迭代器在遍历时直接访问集合中的内容并且在遍历过程中使用一个modCount变量。集合在被遍历期间如果内容发生变化就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前都会检测modCount变量是否为expectedmodCount值是的话就返回遍历否则抛出异常终止遍历。注意这里异常的抛出条件是检测到modCount ! expectedmodCount这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值则异常不会抛出。因此不能依赖于这个异常是否抛出而进行并发操作的编程这个异常只建议用于检测并发修改的bug。场景java.util包下的集合类都是快速失败的不能在多线程下发生并发修改迭代过程中被修改比如ArrayList 类。 安全失败fail—safe 采用安全失败机制的集合容器在遍历时不是直接在集合内容上访问的而是先复制原有集合内容在拷贝的集合上进行遍历。原理由于迭代时是对原集合的拷贝进行遍历所以在遍历过程中对原集合所作的修改并不能被迭代器检测到所以不会触发Concurrent Modification Exception。缺点基于拷贝内容的优点是避免了Concurrent Modification Exception但同样地迭代器并不能访问到修改后的内容即迭代器遍历的是开始遍历那一刻拿到的集合拷贝在遍历期间原集合发生的修改迭代器是不知道的。场景java.util.concurrent包下的容器都是安全失败可以在多线程下并发使用并发修改比如CopyOnWriteArrayList类。 6.有哪几种实现ArrayList线程安全的方法 fail-fast是一种可能触发的机制实际上ArrayList的线程安全仍然没有保证一般保证ArrayList的线程安全可以通过这些方案 使用Vector 代替ArrayList。不推荐Vector是一个历史遗留类使用Collections.synchronizedList包装ArrayList然后操作包装后的list。使用 CopyOnWriteArrayList 代替 ArrayList。在使用 ArrayList 时应用程序通过同步机制去控制 ArrayList 的读写。 7.CopyOnWriteArrayList了解多少 CopyOnWriteArrayList就是线程安全版本的ArrayList。 它的名字叫 copyOnwrite——写时复制已经明示了它的原理。 CopyOnWriteArrayList采用了一种读写分离的并发策略。CopyOnWriteArrayList容器允许并发读读操作是无锁的性能较高。至于写操作比如向容器中添加一个元素则首先将当前容器复制一份然后在新副本上执行写操作结束之后再将原容器的引用指向新容器。 Map Map中毫无疑问最重要的就是HashMap面试基本被盘出包浆了各种问法一定要好好准备。 8.能说一下HashMap的数据结构吗 JDK1.7的数据结构是**数组链表**JDK1.7还有人在用不会吧… 说一下JDK1.8的数据结构吧 JDK1.8的数据结构是**数组链表红黑树。** 数据结构示意图如下 其中桶数组是用来存储数据元素链表是用来解决冲突红黑树是为了提高查询的效率。 数据元素通过映射关系也就是散列函数映射到桶数组对应索引的位置如果发生冲突从冲突的位置拉一个链表插入冲突的元素如果链表长度8 数组大小64链表转为红黑树如果红黑树节点个数6转为链表 9.你对红黑树了解多少为什么不用二叉树/平衡树呢 红黑树本质上是一种二叉查找树为了保持平衡它又在二叉查找树的基础上增加了一些规则 每个节点要么是红色要么是黑色根节点永远是黑色的所有的叶子节点都是是黑色的注意这里说叶子节点其实是图中的NULL节点每个红色节点的两个子节点一定都是黑色从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点 之所以不用二叉树 红黑树是一种平衡的二叉树插入、删除、查找的最坏时间复杂度都为O(logn)避免了二叉树最坏情况下的O(n)时间复杂度。 之所以不用平衡二叉树 平衡二叉树是比红黑树更严格的平衡树为了保持保持平衡需要旋转的次数更多也就是说平衡二叉树保持平衡的效率更低所以平衡二叉树插入和删除的效率比红黑树要低。 10.红黑树怎么保持平衡的知道吗 红黑树有两种方式保持平衡旋转 和 染色。 旋转旋转分为两种左旋和右旋 染色变换红黑的颜色 11.HashMap的put流程知道吗 先上个流程图吧 首先进行哈希值的扰动,获取一个新的哈希值。(key null) ? 0 : (h key.hashCode()) ^ (h 16); 判断tab是否位空或者长度为0如果是则进行扩容操作. if((tab table) null || (n tab.length) 0)n (tab resize()).length;根据哈希值计算下标,如果对应下标正好没有存放数据,则直接插入即可否则需要覆盖。tab[i(n-1) hash]) 判断tab[i]是否为树节点否 则向链表中插入数据是 则向树中插入节点. 如果链表中插入节点的时候链表长度大于等于8则需要把链表转换为红黑树。treeifyBin(tab, hash); 最后所有元素处理完成后判断是否超过阈值threshold超过则扩容。 12.HashMap怎么查找元素的呢 先看流程图 HashMap的查找就简单很多 使用扰动函数获取新的哈希值计算数组下标获取节点当前节点和key匹配直接返回否则当前节点是否为树节点查找红黑树否则遍历链表查找 13.HashMap的哈希/扰动函数是怎么设计的 HashMap的哈希函数是先拿到 key的hashCode是一个32位的int类型的数值然后让hashCode的高16位和低16位进行异或操作。 hashCode() 的作用是获取哈希码也称为散列码它实际上是返回一个int 整数定义在 Object 类中是一个本地方法这个方法通常用来将对象的内存地址转换为整数之后返回。 static final int hash(Object key) {int h;// key的hashCode和key的hashCode右移16位做异或运算return (key null) ? 0 : (h key.hashCode()) ^ (h 16); }这么设计是为了降低哈希碰撞的概率。 14.为什么哈希/扰动函数能降hash碰撞 因为 key.hashCode()函数调用的是 key 键值类型自带的哈希函数返回 int 型散列值。int值范围为-2147483648-2147483647加起来大概40亿的映射空间。 只要哈希函数映射得比较均匀松散一般应用是很难出现碰撞的。但问题是一个40亿长度的数组内存是放不下的。 假如HashMap数组的初始大小才16就需要用之前需要对数组的长度取模运算得到的余数才能用来访问数组下标。 源码中模运算就是把散列值和**数组长度-1 **做一个与操作位运算比取余%运算要快。 bucketIndex indexFor(hash, table.length);static int indexFor(int h, int length) {return h (length-1); }顺便说一下这也正好解释了为什么HashMap的数组长度要取 2 的整数幂。 因为这样数组长度-1正好相当于一个低位掩码。与操作的结果就是散列值的高位全部归零只保留低位值用来做数组下标访问。 以初始长度16为例16-115。2进制表示是0000 0000 0000 0000 0000 0000 0000 1111。和某个散列值做与操作如下结果就是截取了最低的四位值。 这样是要快捷一些但是新的问题来了就算散列值分布再松散要是只取最后几位的话碰撞也会很严重。如果散列本身做得不好分布上成等差数列的漏洞如果正好让最后几个低位呈现规律性重复那就更难搞了。 这时候 扰动函数 的价值就体现出来了看一下扰动函数的示意图 右移16位正好是32bit的一半自己的高半区和低半区做异或就是为了混合原始哈希码的高位和低位以此来加大低位的随机性。而且混合后的低位掺杂了高位的部分特征这样高位的信息也被变相保留下来。 15.为什么HashMap的容量是2的倍数呢 第一个原因是为了方便哈希取余 将元素放在table数组上面是用hash值%数组大小定位位置而HashMap是用hash值数组大小-1却能和前面达到一样的效果这就得益于HashMap的大小是2的倍数2的倍数意味着该数的二进制位只有一位为1而该数-1就可以得到二进制位上1变成0后面的0变成1再通过运算就可以得到和%一样的效果并且位运算比%的效率高得多 HashMap的容量是2的n次幂时n-1的2进制也就是1111111***111这样形式的这样与添加元素的hash值进行位运算时能够充分的散列使得添加的元素均匀分布在HashMap的每个位置上减少hash碰撞。 第二个方面是在扩容时利用扩容后的大小也是2的倍数将已经产生hash碰撞的元素完美的转移到新的table中去 我们可以简单看看HashMap的扩容机制HashMap中的元素在超过负载因子*HashMap大小时就会产生扩容。 modCount; if (size threshold)resize(); afterNodeInsertion(evict); return null;put时当大小超过threshold就会扩容。 16.如果初始化HashMap传一个17的值new HashMap它会怎么处理 简单来说就是初始化时传的不是2的倍数时HashMap会向上寻找离得最近的2的倍数所以传入17但HashMap的实际容量是32。 我们来看看详情在HashMap的初始化中有这样一段方法 public HashMap(int initialCapacity, float loadFactor) {...this.loadFactor loadFactor;this.threshold tableSizeFor(initialCapacity); }阀值threshold通过方法tableSizeFor进行计算是根据初始化传的参数来计算的。同时这个方法也要要寻找比初始值大的最小的那个2进制数值。比如传了17我应该找到的是32。 static final int tableSizeFor(int cap) {int n cap - 1;n | n 1;n | n 2;n | n 4;n | n 8;n | n 16;return (n 0) ? 1 : (n MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n 1; }MAXIMUM_CAPACITY 1 30这个是临界范围也就是最大的Map集合。计算过程是向右移位1、2、4、8、16和原来的数做|运算这主要是为了把二进制的各个位置都填上1当二进制的各个位置都是1以后就是一个标准的2的倍数减1了最后把结果加1再返回即可。 以17为例看一下初始化计算table容量的过程 17.你还知道哪些哈希函数的构造方法呢 HashMap里哈希构造函数的方法叫 除留取余法H(key)key%p (pN)关键字除以一个不大于哈希表长度的正整数p所得余数为地址当然HashMap里进行了优化改造效率更高散列也更均衡。 除此之外还有这几种常见的哈希函数构造方法 直接定址法 直接根据 key 来映射到对应的数组位置例如1232放到下标1232的位置。数字分析法 取key的某些数字例如十位和百位作为映射的位置平方取中法 取key平方的中间几位作为映射的位置折叠法 将key分割成位数相同的几段然后把它们的叠加和作为映射的位置 18.解决哈希冲突有哪些方法呢 我们到现在已经知道HashMap使用链表的原因为了处理哈希冲突这种方法就是所谓的 链地址法在冲突的位置拉一个链表把冲突的元素放进去。 除此之外还有一些常见的解决冲突的办法 开放定址法开放定址法就是从冲突的位置再接着往下找给冲突元素找个空位。 找到空闲位置的方法也有很多种 线行探查法从冲突的位置开始依次判断下一个位置是否空闲直至找到空闲位置平方探查法从冲突的位置x开始第一次增加 1^2 个位置第二次增加 2^2…直至找到空闲的位置 再哈希法换种哈希函数重新计算冲突元素的地址。 建立公共溢出区再建一个数组把冲突的元素放进去。 19.为什么HashMap链表转红黑树的阈值为8呢 树化发生在table数组的长度大于64且链表的长度大于8的时候。 为什么是8呢源码的注释也给出了答案。 红黑树节点的大小大概是普通节点大小的两倍所以转红黑树牺牲了空间换时间更多的是一种兜底的策略保证极端情况下的查找效率。 阈值为什么要选8呢和统计学有关。理想情况下使用随机哈希码链表里的节点符合泊松分布出现节点个数的概率是递减的节点个数为8的情况发生概率仅为0.00000006。 至于红黑树转回链表的阈值为什么是6而不是8是因为如果这个阈值也设置成8假如发生碰撞节点增减刚好在8附近会发生链表和红黑树的不断转换导致资源浪费。 20.扩容在什么时候呢为什么扩容因子是0.75 为了减少哈希冲突发生的概率当前HashMap的元素个数达到一个临界值的时候就会触发扩容把所有元素rehash之后再放在扩容后的容器中这是一个相当耗时的操作。 而这个临界值threshold就是由加载因子和当前容器的容量大小来确定的假如采用默认的构造方法 临界值threshold 默认容量DEFAULT_INITIAL_CAPACITY*默认扩容因子DEFAULT_LOAD_FACTOR 那就是大于16x0.7512时就会触发扩容操作。 那么为什么选择了0.75作为HashMap的默认加载因子呢 简单来说这是对 空间 成本和 时间 成本平衡的考虑。 在HashMap中有这样一段注释 作为一般规则默认负载因子.75在时间和空间成本之间提供了良好的折衷。较高的值会减少空间开销但会增加查找成本反映在HashMap类的大多数操作中包括get和put。在设置其初始容量时应考虑映射中的预期条目数量及其负载系数以最大限度地减少再哈希操作的次数。如果初始容量大于最大条目数除以负载系数则不会发生再哈希操作。 我们都知道HashMap的散列构造方式是Hash取余负载因子决定元素个数达到多少时候扩容。 假如我们设的比较大元素比较多空位比较少的时候才扩容那么发生哈希冲突的概率就增加了查找的时间成本就增加了。 我们设的比较小的话元素比较少空位比较多的时候就扩容了发生哈希碰撞的概率就降低了查找时间成本降低但是就需要更多的空间去存储元素空间成本就增加了。 21.那扩容机制了解吗 HashMap是基于数组链表和红黑树实现的但用于存放key值的桶数组的长度是固定的由初始化参数确定。 那么随着数据的插入数量增加以及负载因子的作用下就需要扩容来存放更多的数据。而扩容中有一个非常重要的点就是jdk1.8中的优化操作可以不需要再重新计算每一个元素的哈希值。 因为HashMap的初始容量是2的次幂扩容之后的长度是原来的二倍新的容量也是2的次幂所以元素要么在原位置要么在原位置再移动2的次幂。 看下这张图n为table的长度图a 表示扩容前的key1和key2两种key确定索引的位置图b表示扩容后key1和key2两种key确定索引位置。 元素在重新计算hash之后因为n变为2倍那么n-1的mask范围在高位多1bit红色因此新的index就会发生这样的变化 所以在扩容时只需要看原来的hash值新增的那一位是0还是1就行了是0的话索引没变是1的化变成**原索引oldCap**看看如16扩容为32的示意图 扩容节点迁移主要逻辑 if (e.next null)newTab[e.hash (newCap - 1)] e; else if (e instanceof TreeNode)//树节点分割((TreeNodeK,V)e).split(this, newTab, j, oldCap); else{ //preserve order//链表拆成两个链表lo、hi两个链表的头、尾节点NodeK,V loHead null, loTail null;NodeK,V hiHead null, hiTail null;NodeK,V next;do {//遍历链表将节点放到相应的新链表next e.next;if ((e.hash oldCap) 0) {if (loTail null)loHead e;else loTail.next e;loTail e;}else {if (hiTail null)hiHead e;elsehiTail.next e;hiTail e;}} while ((e next) ! null);//lo链表放到新table原位置if (loTail ! null) {loTail.next null;newTab[j] loHead;}//hi链表放到joldCap位置if (hiTail ! null) {hiTail.next null;newTab[j oldCap] hiHead;} }22.jdk1.8对HashMap主要做了哪些优化呢为什么 jdk1.8 的HashMap主要有五点优化 数据结构数组链表改成了数组链表或红黑树 原因发生hash冲突元素会存入链表链表过长转为红黑树将时间复杂度由O(n)降为O(logn) 链表插入方式链表的插入方式从头插法改成了尾插法 简单说就是插入时如果数组位置上已经有元素1.7将新元素放到数组中原始节点作为新节点的后继节点1.8 遍历链表将元素放置到链表的最后。 原因因为1.7头插法扩容时头插法会使链表发生反转多线程环境下会产生环。 扩容rehash扩容的时候1.7需要对原数组中的元素进行重新hash定位在新数组的位置1.8采用更简单的判断逻辑不需要重新通过哈希函数计算位置新的位置不变或索引 新增容量大小。 原因提高扩容的效率更快地扩容。 扩容时机在插入时1.7先判断是否需要扩容再插入1.8先进行插入插入完成再判断是否需要扩容 散列函数1.7 做了四次移位和四次异或jdk1.8只做一次。 原因做 4 次的话边际效用也不大改为一次提升效率。 23.你能自己设计实现一个HashMap吗 这道题快手常考。 不要慌红黑树版咱们多半是写不出来但是数组链表版还是问题不大的详细可见手写HashMap快手面试官直呼内行。 整体的设计 散列函数hashCode() 除留余数法冲突解决链地址法扩容节点重新hash获取位置 完整代码 24.HashMap是线程安全的吗多线程下会有什么问题 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 中都存在。 25.有什么办法能解决HashMap线程不安全的问题呢 Java中有HashTable、Collections.synchronizedMap、以及ConcurrentHashMap可以实现线程安全的Map。 HashTable 是直接在操作方法上加 synchronized 关键字锁住整个table数组粒度比较大Collections.synchronizedMap 是使用 Collections 集合工具的内部类通过传入 Map 封装出一个SynchronizedMap对象内部定义了一个对象锁方法内通过对象锁实现ConcurrentHashMap在jdk1.7中使用分段锁在jdk1.8中使用CASsynchronized。 26.能具体说一下ConcurrentHashmap的实现吗 ConcurrentHashmap线程安全在jdk1.7版本是基于分段锁实现在jdk1.8是基于CAssynchronized实现。 1.7分段锁 从结构上说1.7版本的ConcurrentHashMap采用分段锁机制里面包含一个Segment数组Segment继承于ReentrantLockSegment则包含HashEntry的数组HashEntry本身就是一个链表的结构具有保存keyvalue的能力能指向下一个节点的指针。 实际上就是相当于每个Segment都是一个HashMap默认的Segment长度是16也就是支持16个线程的并发写Segment之间相互不会受到影响。 put流程 整个流程和HashMap非常类似只不过是先定位到具体的Segment然后通过ReentrantLock去操作而已后面的流程就和HashMap基本上是一样的。 计算hash定位到segmentsegment如果是空就先初始化使用ReentrantLock加锁如果获取锁失败则尝试自旋自旋超过次数就阻塞获取保证一定获取锁成功遍历HashEntry就是和HashMap一样数组中key和hash一样就直接替换不存在就再插入链表链表同样操作 get流程 get也很简单key通过hash定位到segment再遍历链表定位到具体的元素上需要注意的是value是volatile的所以get是不需要加锁的。 1.8 CASsynchronized CAS的全称为Compare-And-Swap直译就是对比交换。是一条CPU的原子指令其作用是让CPU先进行比较两个值是否相等然后原子地更新某个位置的值。 CAS操作需要输入两个数值一个旧值(期望操作前的值)和一个新值在操作期间先比较下在旧值有没有发生变化如果没有发生变化才交换成新值发生了变化则不交换。 jdk1.8实现线程安全不是在数据结构上下功夫它的数据结构和HashMap是一样的数组链表红黑树。它实现线程安全的关键点在于put流程。 put流程 首先计算hash遍历node数组如果node是空的话就通过CAS自旋的方式初始化如果当前数组位置是空则直接通过CAS自旋写入数据如果hashMOVED说明需要扩容执行扩容如果都不满足就使用synchronized写入数据写入数据同样判断链表、红黑树链表写入和HashMap的方式一样key hash一样就覆盖反之就尾插法链表长度超过8就转换成红黑树 get查询 get很简单和HashMap基本相同通过key计算位置table该位置key相同就返回如果是红黑树按照红黑树获取否则就遍历链表获取。 27.HashMap内部节点是有序的吗 HashMap是无序的根据hash值随机插入。如果想使用有序的Map可以使用LinkedHashMap或者TreeMap。 28.讲讲LinkedHashMap怎么实现有序的 LinkedHashMap维护了一个双向链表有头尾节点同时LinkedHashMap节点Entry内部除了继承HashMap的Node属性还有 before和 after用于标识前置节点和后置节点。 可以实现按插入的顺序或访问顺序排序。 29.讲讲TreeMap怎么实现有序的 TreeMap是按照Key的自然顺序或者Comprator的顺序进行排序内部是通过红黑树来实现。所以要么key所属的类实现Comparable接口或者自定义一个实现了Comparator接口的比较器传给TreeMap用于key的比较。 Set Set面试没啥好问的拿HashSet来凑个数。 30.讲讲HashSet的底层实现 HashSet底层就是基于HashMap实现的。HashSet的源码非常非常少因为除了clone()、writeObject()、readObject()是 HashSet自己不得不实现之外其他方法都是直接调用 HashMap 中的方法。 HashSet的add方法直接调用HashMap的put方法将添加的元素作为keynew一个Object作为value直接调用HashMap的put方法它会根据返回值是否为空来判断是否插入元素成功。 public boolean add(E e) {return map.put(e, PRESENT)null; }资料来源地址面渣逆袭Java集合连环三十问
文章转载自:
http://www.morning.jtjmz.cn.gov.cn.jtjmz.cn
http://www.morning.jfbpf.cn.gov.cn.jfbpf.cn
http://www.morning.gfznl.cn.gov.cn.gfznl.cn
http://www.morning.fnpmf.cn.gov.cn.fnpmf.cn
http://www.morning.ddzqx.cn.gov.cn.ddzqx.cn
http://www.morning.grzpc.cn.gov.cn.grzpc.cn
http://www.morning.lwgsk.cn.gov.cn.lwgsk.cn
http://www.morning.cnwpb.cn.gov.cn.cnwpb.cn
http://www.morning.lwsct.cn.gov.cn.lwsct.cn
http://www.morning.hnk25076he.cn.gov.cn.hnk25076he.cn
http://www.morning.mlzyx.cn.gov.cn.mlzyx.cn
http://www.morning.bpmdx.cn.gov.cn.bpmdx.cn
http://www.morning.gmysq.cn.gov.cn.gmysq.cn
http://www.morning.wschl.cn.gov.cn.wschl.cn
http://www.morning.cjmmt.cn.gov.cn.cjmmt.cn
http://www.morning.zqcsj.cn.gov.cn.zqcsj.cn
http://www.morning.xzrbd.cn.gov.cn.xzrbd.cn
http://www.morning.dwxqf.cn.gov.cn.dwxqf.cn
http://www.morning.lzwfg.cn.gov.cn.lzwfg.cn
http://www.morning.sqyjh.cn.gov.cn.sqyjh.cn
http://www.morning.bkqw.cn.gov.cn.bkqw.cn
http://www.morning.wpxfk.cn.gov.cn.wpxfk.cn
http://www.morning.qzxb.cn.gov.cn.qzxb.cn
http://www.morning.spxsm.cn.gov.cn.spxsm.cn
http://www.morning.bfmq.cn.gov.cn.bfmq.cn
http://www.morning.fwjfh.cn.gov.cn.fwjfh.cn
http://www.morning.qwhbk.cn.gov.cn.qwhbk.cn
http://www.morning.kpqjr.cn.gov.cn.kpqjr.cn
http://www.morning.qkbwd.cn.gov.cn.qkbwd.cn
http://www.morning.smygl.cn.gov.cn.smygl.cn
http://www.morning.rykn.cn.gov.cn.rykn.cn
http://www.morning.kflbf.cn.gov.cn.kflbf.cn
http://www.morning.ftmp.cn.gov.cn.ftmp.cn
http://www.morning.gnkdp.cn.gov.cn.gnkdp.cn
http://www.morning.bxqry.cn.gov.cn.bxqry.cn
http://www.morning.pqsys.cn.gov.cn.pqsys.cn
http://www.morning.tdxnz.cn.gov.cn.tdxnz.cn
http://www.morning.kflbf.cn.gov.cn.kflbf.cn
http://www.morning.jstggt.cn.gov.cn.jstggt.cn
http://www.morning.sqgsx.cn.gov.cn.sqgsx.cn
http://www.morning.rwlnk.cn.gov.cn.rwlnk.cn
http://www.morning.skrcn.cn.gov.cn.skrcn.cn
http://www.morning.kbdrq.cn.gov.cn.kbdrq.cn
http://www.morning.tlyms.cn.gov.cn.tlyms.cn
http://www.morning.srnth.cn.gov.cn.srnth.cn
http://www.morning.hksxq.cn.gov.cn.hksxq.cn
http://www.morning.ie-comm.com.gov.cn.ie-comm.com
http://www.morning.pslzp.cn.gov.cn.pslzp.cn
http://www.morning.trhrk.cn.gov.cn.trhrk.cn
http://www.morning.tqfnf.cn.gov.cn.tqfnf.cn
http://www.morning.gcthj.cn.gov.cn.gcthj.cn
http://www.morning.znqztgc.cn.gov.cn.znqztgc.cn
http://www.morning.hsrpc.cn.gov.cn.hsrpc.cn
http://www.morning.dyrzm.cn.gov.cn.dyrzm.cn
http://www.morning.pflpb.cn.gov.cn.pflpb.cn
http://www.morning.qkxt.cn.gov.cn.qkxt.cn
http://www.morning.ymmjx.cn.gov.cn.ymmjx.cn
http://www.morning.xmbhc.cn.gov.cn.xmbhc.cn
http://www.morning.zfzgp.cn.gov.cn.zfzgp.cn
http://www.morning.dmzqd.cn.gov.cn.dmzqd.cn
http://www.morning.jfcbz.cn.gov.cn.jfcbz.cn
http://www.morning.ggtgl.cn.gov.cn.ggtgl.cn
http://www.morning.fpczq.cn.gov.cn.fpczq.cn
http://www.morning.nfdty.cn.gov.cn.nfdty.cn
http://www.morning.kqnwy.cn.gov.cn.kqnwy.cn
http://www.morning.lhrwy.cn.gov.cn.lhrwy.cn
http://www.morning.pyncx.cn.gov.cn.pyncx.cn
http://www.morning.bmncq.cn.gov.cn.bmncq.cn
http://www.morning.whclz.cn.gov.cn.whclz.cn
http://www.morning.prgyd.cn.gov.cn.prgyd.cn
http://www.morning.bnrff.cn.gov.cn.bnrff.cn
http://www.morning.kwqt.cn.gov.cn.kwqt.cn
http://www.morning.fygbq.cn.gov.cn.fygbq.cn
http://www.morning.ymmjx.cn.gov.cn.ymmjx.cn
http://www.morning.mksny.cn.gov.cn.mksny.cn
http://www.morning.qcygd.cn.gov.cn.qcygd.cn
http://www.morning.hlmkx.cn.gov.cn.hlmkx.cn
http://www.morning.zrbpx.cn.gov.cn.zrbpx.cn
http://www.morning.zcxjg.cn.gov.cn.zcxjg.cn
http://www.morning.bnbzd.cn.gov.cn.bnbzd.cn
http://www.tj-hxxt.cn/news/271070.html

相关文章:

  • 用html5做课程教学网站个人在百度上发广告怎么发
  • 南京高端网站制作公司哪家好网站开发的关键计算机资源计划
  • 网上教学网站建设python创建网站
  • 苏州高端模板建站装修设计网站排行榜
  • 蚂蚁分类信息网站建设wordpress 木马
  • 三沙网站设计公司公司的网站建设费用怎么入账
  • 网站开发经典案例网页设计与制作课程建设规划方案
  • 在哪个网站上找国外客户做外贸网站开发使用的技术
  • 电子商务网站建设服务外包wordpress怎么实现实时刷新
  • 如何判断网站开发语言wordpress消耗性能吗
  • 做网站毕业设计能过吗专业格泰网站建设
  • 建设网站 安全事项Discuz网站制作教程
  • 网站建设视频l上海建筑设计院地址
  • 吉林省建设安全监督站网站个人网站制作wordpress
  • 专门做产品测评的网站厦门旅游网站建设
  • 一级a做爰片免费网站国语网站怎么后台登陆
  • 益阳网站建设网站wordpress个人中心页
  • 怎么查自己的邮箱号seo推广seo技术培训
  • 个人做的网站能备案吗现在去长沙会被隔离吗
  • 做网站网页的人是不是思维网站SEO优化托管
  • 北京做网站的好公司网络基础架构
  • 论坛网站免费建设模板下载安装铜川有哪些需要网页设计师的公司
  • 泉州科技云网站建设网站建设利益
  • 承德住建局官方网站石家庄网站推广
  • 网站代码查看微信开店小程序怎么弄
  • 建设门户网站的意义科技为了上大学上交可控核聚变笔趣阁
  • 小企业网站建设设计国际新闻最新消息战争视频
  • 怎么做php登陆网站织梦 商城网站
  • 建设银行网站邮箱金山区做网站公司
  • 关于网站制作报价烟台网站建设方案托管