HashSet和CopyOnWriteArraySet
前言
这篇文章的目的如下:
- HashSet是如何保证元素的不重复和无序
- HashSet的增删(改查?)原理
- CopyOnWriteArraySet支持并发的原理
- CopyOnWriteArraySet的增删(改查?)原理
如果不想看分析过程,可直接拉到文章末尾看结论
先来看看 Set接口
public interface Set<E> extends Collection<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean retainAll(Collection<?> c);
boolean removeAll(Collection<?> c);
boolean equals(Object o);
int hashCode();
}
我们从以上接口发现Set并没有get和set方法,也就是没有查和改,为什么呢?原因如下:
- 因为Set是无序的,没有通过index来进行查询
- 同样是因为Set是无序的,也就是没有办法通过Index来进行修改
1 HashSet如何保证元素不重复?
要弄清楚HashSet如何保证里面的元素不重复,得从以下两个方面入手:
- 它底层的存储结构是什么?
- 插入时是如何判断元素是否存在?
当我们弄清楚上面两个问题之后我们也可以明白HashSet为什么是无序的了。
1)HashSet的底层存储逻辑
且看源码:
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable{
static final long serialVersionUID = -5024744406713321676L;
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
...
}
我们可以看出来HashSet的底层存储结构是一个HashMap,并且HashSet的元素作为该Map的Key进行存储,HashMap的Key的存储是无序并且不可重复,这就解释了HashSet中如何保证元素不重复
2)插入逻辑
public boolean add(E e) {return map.put(e, PRESENT)==null;}
直接put到map当中
3)总结
由以上内容我们可以知道HashSet的底层存储结构是HashMap,并且插入到HashSet中元素作为map的key进行存储,这就保证HashSet的一下特点:
- HashSet中的元素不重复的
- HashSet中的元素是无序的
2 HashSet增删(改查?)原理
我们从上一小节了解到HashSet的底层存储结构是HashMap,那么它的增删也就是map的put和remove
1)增
public boolean add(E e) {return map.put(e, PRESENT)==null;}
直接put到map当中
2)删
public boolean remove(Object o) {return map.remove(o)==PRESENT;}
直接在map中移除即可,非常简单
3 CopyOnWriteArraySet为什么能支持并发?
在搞清楚CopyOnWriteArraySet为什么能支持并发 这个问题之前,我们先来想想以下几个问题:
- HashSet对应的并发类为什么叫CopyOnWriteArraySet,而不是叫CopyOnWriteHashSet呢?
- CopyOnWriteArraySet和CopyOnWriteArrayList有没有关系?
我想一旦我们弄清楚上面两个问题我们就是知道 CopyOnWriteArraySet为什么能支持并发?
了
先来看看CopyOnWriteArraySet的部分源码:
public class CopyOnWriteArraySet<E> extends AbstractSet<E>
implements java.io.Serializable {
private static final long serialVersionUID = 5457747651344034263L;
private final CopyOnWriteArrayList<E> al;
/**
* Creates an empty set.
*/
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
...
}
从源码中神奇地发现CopyOnWriteArraySet的底层存储结构竟然是CopyOnWriteArrayList,那么我们就可以知道它的名字的由来了,并且知道它支持并发的原理跟CopyOnWriteArrayList是一样的。
4 CopyOnWriteArraySet的增删(改查?)原理
1)增
public boolean add(E e) {
return al.addIfAbsent(e);
}
看方法名我们就是如果CopyOnWriteArrayList中不存在某元素才会添加成功
2)删
public boolean remove(Object o) {
return al.remove(o);
}
直接从CopyOnWriteArrayList中移除
5 总结
- HashSet是如何保证元素的不重复和无序
答:因为HashSet的底层存储结构是HashMap,并且HashSet中的元素是作为Map的Key存储到Map中,所以HashMap中Key是不重复且无序,所以HashSet中的元素也就是不重复和无序的
- HashSet的增删(改查?)原理
HashSet的增删原理很简单,就是map的put和remove,为什么没有改查呢?那是因为HashSet中的元素是无序的,没办法根据索引进行查询和修改
- CopyOnWriteArraySet支持并发的原理
CopyOnWriteArraySet之所以叫CopyOnWriteArraySet,是因为它的底层存储结构是CopyOnWriteArrayList,同时也就是保证了它的并发安全性
- CopyOnWriteArraySet的增删(改查?)原理
CopyOnWriteArraySet继承了AbstractSet,跟HashSet一样只有增删,没有改查,增删原理也就是调用CopyOnWriteArrayList的增删方法,只不过增的时候需要判断一下List中是否存储该元素
HashSet和CopyOnWriteArraySet的更多相关文章
- HashSet和CopyOnWriteArraySet(转载)
前言 这篇文章的目的如下: HashSet是如何保证元素的不重复和无序 HashSet的增删(改查?)原理 CopyOnWriteArraySet支持并发的原理 CopyOnWriteArraySet ...
- HashSet、CopyOnWriteArraySet、ConcurrentSkipListSet源码解析(JDK1.8)
目录 HashSet源码解析 HashSet简单使用的demo HashSet中的变量 HashSet的构造函数 HashSet的add方法 HashSet的iterator方法 HashSet的si ...
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
概要 本章是JUC系列中的CopyOnWriteArraySet篇.接下来,会先对CopyOnWriteArraySet进行基本介绍,然后再说明它的原理,接着通过代码去分析,最后通过示例更进一步的了解 ...
- ArrayList和CopyOnWriteArrayList
这篇文章的目的如下: 了解一下ArrayList的增删改查实现原理 看看为什么说ArrayList查询快而增删慢? CopyOnWriteArrayList为什么并发安全且性能比Vector好 1. ...
- JUC (java.util.concurrent)
1.什么是线程?什么是进程? 2.多线程的状态? public enum State { //6种状态 NEW, RUNNABLE, //可运行 BLOCKED, //阻塞 WAITING, //等待 ...
- CopyOnWriteArrayList的增删改查实现原理
https://www.cnblogs.com/simple-focus/p/7439919.html 篇文章的目的如下: 了解一下ArrayList和CopyOnWriteArrayList的增删改 ...
- Java并发包——线程安全的Collection相关类
Java并发包——线程安全的Collection相关类 摘要:本文主要学习了Java并发包下线程安全的Collection相关的类. 部分内容来自以下博客: https://www.cnblogs.c ...
- Java多线程编程基础知识汇总
多线程简介 多任务 现代操作系统(Windows.Linux.MacOS)都可以执行多任务,多任务就是同时运行多个任务.例如在我们的计算机上,一般都同时跑着多个程序,例如浏览器,视频播放器,音乐播 ...
- 狂神说JUC学习笔记(一)
狂神说JUC的原版笔记: 链接:https://pan.baidu.com/s/12zrGI4JyZhmkQh0cqEO4BA 提取码:d65c 我的笔记在狂神的笔记上增加了一些知识点或者做了些许修改 ...
随机推荐
- HDU 2412 Farm Irrigation
题目: Benny has a spacious farm land to irrigate. The farm land is a rectangle, and is divided into a ...
- java中类的加载过程和对象的创建过程
1.类加载过程 首先,jvm在执行时,遇到一个新的类,会先去内存的方法区中去寻找该类的.class文件,如果找到了就直接运行,如果没有找到,则会去硬盘中去寻找该类的.class文件,并将该类文件加载到 ...
- 阻止安卓实体返回键后退的网页js实现
提供两种解决方法吧,都是网上来的,侵权删,毕竟我等只是搞后端的-- 第一种方法: // 阻止安卓实体键后退 // 页面载入时使用pushState插入一条历史记录 history.pushState( ...
- Bootstrap中data-src无法显示图片,但是src可以
在学习bootstrap时,书中的源码是用的data-src来定义图像位置,但是我在使用的时候无法显示图片:data-src可以在img标签中使用来显示图片吗?我使用src可以,而是用data-src ...
- 如何查看dede版本信息
dedecms版本信息 更新日期 it 分类: dedecms 打开 /include/common.inc.php 查找 $cfg_version 可以看到版本号 /打开 data/admin/ve ...
- 获取select中的值
分别使用javascript原生的方法和jquery方法<select id="test" name=""> <option value=&q ...
- JavaScript实现Tab栏切换
本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. 京东网页上,可以看到下面这种tab栏的切换: 我们把模型抽象出来,实现一 ...
- java中的按位与运算
package scanner; public class SingleAnd { public static void main(String[] args) { int[] first = {10 ...
- 【笔记】npm 安装 vue-cli
最近完成了慕课网的 高仿饿了么webApp 课程,对于vue 的认识有了更深一步的认识,但是其脚手架 vue-cli 的安装流程还是有点懵,于是今天重新试了一遍加深认识 网上参考过一些有用的教程在这里 ...
- 关于jwplayer 处理进度条禁止快进的处理方法。
今天在处理一个关于jwplayer 第一次播放禁止快进,但是可以后退的一个需求.开始在网上去查一些方法,有几个方法是换皮肤,禁止点击,但是和我的初衷不是很一致,还有一种方式是官网查看了API接口的方 ...