前言

这篇文章的目的如下:

  • 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是一样的。

附: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的更多相关文章

  1. HashSet和CopyOnWriteArraySet(转载)

    前言 这篇文章的目的如下: HashSet是如何保证元素的不重复和无序 HashSet的增删(改查?)原理 CopyOnWriteArraySet支持并发的原理 CopyOnWriteArraySet ...

  2. HashSet、CopyOnWriteArraySet、ConcurrentSkipListSet源码解析(JDK1.8)

    目录 HashSet源码解析 HashSet简单使用的demo HashSet中的变量 HashSet的构造函数 HashSet的add方法 HashSet的iterator方法 HashSet的si ...

  3. Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet

    概要 本章是JUC系列中的CopyOnWriteArraySet篇.接下来,会先对CopyOnWriteArraySet进行基本介绍,然后再说明它的原理,接着通过代码去分析,最后通过示例更进一步的了解 ...

  4. ArrayList和CopyOnWriteArrayList

    这篇文章的目的如下: 了解一下ArrayList的增删改查实现原理 看看为什么说ArrayList查询快而增删慢? CopyOnWriteArrayList为什么并发安全且性能比Vector好 1. ...

  5. JUC (java.util.concurrent)

    1.什么是线程?什么是进程? 2.多线程的状态? public enum State { //6种状态 NEW, RUNNABLE, //可运行 BLOCKED, //阻塞 WAITING, //等待 ...

  6. CopyOnWriteArrayList的增删改查实现原理

    https://www.cnblogs.com/simple-focus/p/7439919.html 篇文章的目的如下: 了解一下ArrayList和CopyOnWriteArrayList的增删改 ...

  7. Java并发包——线程安全的Collection相关类

    Java并发包——线程安全的Collection相关类 摘要:本文主要学习了Java并发包下线程安全的Collection相关的类. 部分内容来自以下博客: https://www.cnblogs.c ...

  8. Java多线程编程基础知识汇总

    多线程简介 多任务   现代操作系统(Windows.Linux.MacOS)都可以执行多任务,多任务就是同时运行多个任务.例如在我们的计算机上,一般都同时跑着多个程序,例如浏览器,视频播放器,音乐播 ...

  9. 狂神说JUC学习笔记(一)

    狂神说JUC的原版笔记: 链接:https://pan.baidu.com/s/12zrGI4JyZhmkQh0cqEO4BA 提取码:d65c 我的笔记在狂神的笔记上增加了一些知识点或者做了些许修改 ...

随机推荐

  1. 自实现PC端jQuery版轮播图

    最近其他项目不是很忙,被安排给公司的官网项目做一个新的页面(之前没接触公司官网项目),其中有一个用到轮播图的地方,最开始想直接用swiper.js插件实现就好了,可是发现官网项目里之前都没有引入过sw ...

  2. 零基础教你写python爬虫

    大家都知道python经常被用来做爬虫,用来在互联网上抓取我们需要的信息. 使用Python做爬虫,需要用到一些包: requests urllib BeautifulSoup 等等,关于python ...

  3. 安装Wamp后 Apache无法启动的解决方法

    安装Wamp后 Apache无法启动的解决方法,网上的解决方案可以说是五花八门,有些说了一大推,一点作用都起不到. 其实解决方法只需两步: 1.安装路径不能包含有中文,这个我不知道为什么,总之如果安装 ...

  4. VisualSVN Server启动错误(0x8007042a)

    SVN Server启动错误(0x8007042a)   原因是SVN Server端口被占用 打开VisualSVN Server, 菜单->操作->Properties->Net ...

  5. Android-第三天

    今天开始做一个提交的页面,本来是用LinearLayout,但是这种布局要使用到多组LinearLayout,于是采用表格布局+相对布局的方式. <TableLayout> <Tab ...

  6. 读懂 Deployment YAML - 每天5分钟玩转 Docker 容器技术(125)

    既然要用 YAML 配置文件部署应用,现在就很有必要了解一下 Deployment 的配置格式,其他 Controller(比如 DaemonSet)非常类似. 还是以 nginx-deploymen ...

  7. mysql 中文乱码

  8. servlet多线程问题

    Servlet本身是单实例的,这样当多个用户同时访问某个Servlet时,会访问该唯一的Servlet实例中的成员变量,如果对成员变量进行写入工作,那就会导致Servlet的多线程问题,即数据不一致. ...

  9. IDEA翻译插件推荐Translation 安装和使用以及快捷键绑定

    首先第一步是安装该插件 如图: File -> setting -->plugins 进入该页面,点击如图所示按钮. 然后搜索 Translation 如图: 我们需要的结果一般都不会排在 ...

  10. python编程理念

    在python控制台输入import this之后输出如下: The Zen of Python, by Tim PetersBeautiful is better than ugly.Explici ...