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 我的笔记在狂神的笔记上增加了一些知识点或者做了些许修改 ...
随机推荐
- 最小生成数之Kruskal算法
描述 随着小Hi拥有城市数目的增加,在之间所使用的Prim算法已经无法继续使用了--但是幸运的是,经过计算机的分析,小Hi已经筛选出了一些比较适合建造道路的路线,这个数量并没有特别的大. 所以问题变成 ...
- Oracle_子查询
Oracle_子查询 子查询 --如何查得所有比"CLARK"工资高的员工的信息 select ename, sal from emp where ename = 'CLARK ...
- Oracle临时表空间组
Oracle 10g之前,同一用户的多个会话只可以使用同一个临时表空间,因为在给定的时间只有一个临时表空间默认给用户,为了解决这个潜在的瓶颈,Oracle支持临时表空间组即包含多个临时表空间的集合.临 ...
- eclipse导入项目之后报错
一.项目本身就有错 二.jdk版本的问题 参考网址:http://jingyan.baidu.com/article/95c9d20da3ec5fec4e756186.html 从别的地方导入一个项目 ...
- ceph rbd 封装api
1.安装python,uwsgi,nginx环境 pip安装省略 yumgroupinstall"Developmenttools" yuminstallzlib-develbzi ...
- mysql存储过程且mybatis调用
首先,需要执行符DELIMITER ,建议用//,即在存储过程开始前定义delimiter //,在结束后加上//,最后加上DELIMITER ; 具体原因@参考文章1写的很清楚,不再赘述. 参考文章 ...
- mavean的依赖传递和排除依赖
三个mavean项目 A .B. C 如果B依赖A(A先执行clean package命令) 那么B得pom.xml文件里面就写 <dependency> <groupId> ...
- 带有 thead、tbody 以及 tfoot 元素的 HTML 表格
设置样式: <head><style type="text/css">thead {color:green}tbody {color:blue;height ...
- java web response提供文件下载功能
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
- git 对 Microsoft Word 进行版本控制
昨天中国高校发生了一件骇人听闻的事情,听说不少高校的校园网用户连接校园网被勒索病毒给黑了,重要文件全部被加密,必须要支付赎金才能解密,具体新闻可以参见:http://www.sohu.com/a/14 ...