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 我的笔记在狂神的笔记上增加了一些知识点或者做了些许修改 ...
随机推荐
- java实现单链表常见操作
一.概述: 本文主要总结单链表常见操作的实现,包括链表结点添加.删除:链表正向遍历和反向遍历.链表排序.判断链表是否有环.是否相交.获取某一结点等. 二.概念: 链表: 一种重要的数据结构,HashM ...
- thinkPHP内置字符串截取msubstr函数用法详解
作者:陈达辉 字体:[增加 减小] 类型:转载 时间:2016-11-15 我要评论 这篇文章主要介绍了thinkPHP内置字符串截取函数用法,结合实例形式分析了thinkPHP内置的字符串截取函数功 ...
- linux常用命令(CentOS)
1.目录切换命令 linux目录结构 ps:绿色标注为常用命令 cd xx 切换到该目录下的xx目录 cd ../ 切换到上一层目录 cd / 切换到系统根目录 cd ~ 切换到用户主目录 cd - ...
- Asp.net mvc 中的路由
在 Asp.net mvc 中,来自客户端的请求总是针对某个 Controller 中的 Action 方法,因此,必须采用某种机制从请求的 URl 中解析出对应的 Controller 和 Acti ...
- js解析jsonArray嵌套
{ "data": { "BTC": [ 14781.51, 14888.9, 14900.04, 15098.88, 15308, 14880.01, 149 ...
- vue源码入口文件分析
开发vue项目有段时间了, 之前用angularjs 后来用 reactjs 但是那时候一直没有时间把自己看源码的思考记录下来,现在我不想再浪费这 来之不易的思考, 我要坚持!! 看源码我个人感觉非常 ...
- Oracle问题之literal does not match format string
问题: oerr ora 186101861, 00000, "literal does not match format string"// *Cause: Literals i ...
- ASP.NET没有魔法——ASP.NET MVC 模型绑定
在My Blog中已经有了文章管理功能,可以发布和修改文章,但是对于文章内容来说,这里缺少最重要的排版功能,如果没有排版的博客很大程度上是无法阅读的,由于文章是通过浏览器查看的,所以文章的排版其实与网 ...
- python正则表达式re模块详细介绍
转自:http://www.jb51.net/article/50511.htm 本模块提供了和Perl里的正则表达式类似的功能,不关是正则表达式本身还是被搜索的字符串,都可以是Unicode字符,这 ...
- Windows 性能搜集【perfmon】
为方便问题发生后,问题原因的分析排查,我们可以在服务器中事先开启logman功能搜集服务器的性能数据,方便故障发生后,问题原因的分析排查 Windows服务器部署Permon性能搜集器: 1.使用管理 ...