Java 集合框架分析:线程安全的集合

转载自  Java 集合框架分析:线程安全的集合

 

相关文章: 
Java 集合框架分析:Set 
http://blog.csdn.net/youyou1543724847/article/details/52733723 
Java 集合框架分析:LinkedList 
http://blog.csdn.net/youyou1543724847/article/details/52734935 
Java 集合框架分析:DelayQueue 
http://blog.csdn.net/youyou1543724847/article/details/52176504 
Java 集合框架分析:ArrayBlockingQueue 
http://blog.csdn.net/youyou1543724847/article/details/52174308 
Java 集合框架分析:ArrayDeque 
http://blog.csdn.net/youyou1543724847/article/details/52170026 
Java 集合框架分析:PriorityBlockingQueue 
http://blog.csdn.net/youyou1543724847/article/details/52166985 
Java 集合框架分析:JAVA Queue源码分析 
http://blog.csdn.net/youyou1543724847/article/details/52164895 
Java 集合框架分析:关于Set,Map集合中元素判等的方式 
http://blog.csdn.net/youyou1543724847/article/details/52733766 
Java 集合框架分析:ConcurrentModificationException 
http://blog.csdn.net/youyou1543724847/article/details/52733780 
Java 集合框架分析:线程安全的集合 
http://blog.csdn.net/youyou1543724847/article/details/52734876 
Java 集合框架分析:JAVA集合中的一些边边角角的知识 
http://blog.csdn.net/youyou1543724847/article/details/52734918

说明:同步集合是说它的操作是同步的,(mutative operations :add, set, and so on),但是它的组合操作的同步性要自己控制。

线程安全的集合

什么是线程安全

在多线程环境下,不会产生不一致的行为(线程安全:有一定的标准,能够断定发生的先后顺序,如先获得锁的会执行,然后….)

分类

1.Copy* 
CopyOnWriteArraySet,CopyOnWriteArrayList

2.Blocking* 
ArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, LinkedTransferQueue, PriorityBlockingQueue, SynchronousQueue

3.Concurent* 
ConcurentHashMap, ConcurrentSkipListMap,ConcurrentSkipListSet

CopyOnWriteArrayList

实现:同步的方式是通过在需要修改集合时,通过copy底层的集合数据,在这之上操作。具体表现为: 
1.The “snapshot” style iterator method uses a reference to the state of the array at the point that the iterator was created,迭代器在迭代器被创建时的集合快照上迭代,. This array never changes during the lifetime of the iterator, so interference is impossible and the iterator is guaranteed not to throw ConcurrentModificationException。 
2.The iterator will not reflect additions, removals, or changes to the list since the iterator was created. Element-changing operations on iterators themselves (remove, set, and add) are not supported. These methods throw UnsupportedOperationException。当迭代器创建后,集合上的任何变化都不会反映到迭代器上,通过迭代器进行修改集合会抛出不支持异常。 
简单来说:迭代器在创建后就不变(所引用的集合元素是不变的),集合元素在迭代过程中是可变的。另外,因为迭代器在创建后所引用的集合元素不可变,即通过迭代器进行修改集合的操作都会抛出UnsupportedOperationException异常。 

优缺点: 
1.缺点:copy代价高 
2.优点:迭代快

方法举例:

    public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len + 1);newElements[len] = e;setArray(newElements);return true;} finally {lock.unlock();}

ArrayBlockingQueue

同步通过可重入锁保证

  /** Main lock guarding all access */final ReentrantLock lock;/** Condition for waiting takes */private final Condition notEmpty;/** Condition for waiting puts */private final Condition notFull;

方法举例

    public boolean offer(E e) {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lock();try {if (count == items.length)return false;else {enqueue(e);return true;}} finally {lock.unlock();}}public E poll() {final ReentrantLock lock = this.lock;lock.lock();try {return (count == 0) ? null : dequeue();} finally {lock.unlock();}}

注意:Blocking*系列的提供有多种类似的方法,不同的方法的处理有点不一样。 

这些方法的核心主体还是一样的,但是有的会根据具体的结果会进一步的处理,如:add方法,最终还是调用的offer方法,但是根据offer的返回值(插入成功还是不成功进一步的处理,看是否需要抛出异常)

   public boolean add(E e) {if (offer(e))return true;elsethrow new IllegalStateException("Queue full");}

其中offer和put的区别在offer是用lock.lock(),而put是用的lock.lockInterruptibly()方法进行加锁的,即put方法在等待锁时,你可以中断等待,使线程抛出InterruptedException 异常。(这两个的区别见:http://blog.csdn.net/youyou1543724847/article/details/52174968)

    public void put(E e) throws InterruptedException {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (count == items.length)notFull.await();enqueue(e);} finally {lock.unlock();}}

ConcurentHashMap

这个最令人头疼了,看起源代码来。里面的同步主要是通过CAS操作来保证的。锁的粒度为桶级别,即同一个hashcode的链上的数据会被锁住。

>get操作没有加锁,是通过entry的volatile属性保证可见性。

 public V get(Object key) {Node<K,V>[] tab;Node<K,V> e, p; int n, eh; K ek;int h = spread(key.hashCode());if ((tab = table) != null && (n = tab.length) > 0 &&(e = tabAt(tab, (n - 1) & h)) != null) {if ((eh = e.hash) == h) {if ((ek = e.key) == key || (ek != null && key.equals(ek)))return e.val;}else if (eh < 0)// 树,或是 forwardnode等return (p = e.find(h, key)) != null ? p.val : null;while ((e = e.next) != null) // 链表  {if (e.hash == h &&((ek = e.key) == key || (ek != null && key.equals(ek))))return e.val;}}return null;}
    final V putVal(K key, V value, boolean onlyIfAbsent) {if (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode());int binCount = 0;for (Node<K,V>[] tab = table;;) {Node<K,V> f; int n, i, fh;if (tab == null || (n = tab.length) == 0)tab = initTable();// table为空,初始化table  else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {//如果当前的bin是空的,则通过cas插入,不用加锁if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))break;                   // no lock when adding to empty bin}else if ((fh = f.hash) == MOVED)//检测到正在扩容,则帮助其扩容 tab = helpTransfer(tab, f);else {V oldVal = null;synchronized (f) //对相应的bin进行上锁{if (tabAt(tab, i) == f) //检查锁的有效性,即之前锁住的对象还是bin的头结点,如果无效,则重试(重新走一边for循环){if (fh >= 0) //当前的链还是list结构{binCount = 1;for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash &&((ek = e.key) == key ||(ek != null && key.equals(ek)))) {oldVal = e.val;if (!onlyIfAbsent)e.val = value;break;}Node<K,V> pred = e;if ((e = e.next) == null) {pred.next = new Node<K,V>(hash, key,value, null);break;}}}else if (f instanceof TreeBin)  树节点 {Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;}}}}if (binCount != 0) {if (binCount >= TREEIFY_THRESHOLD)treeifyBin(tab, i);if (oldVal != null)return oldVal;break;}}//插入节点}addCount(1L, binCount);return null;}

总结

在需要使用线程安全的集合时,选择适合的容器非常重要。可通过并发度、性能来考量 
另外,有时候,当数据量较大时,可能这些容器其实已经不太适合,你需要通过别的方法来保证安全,如直接将数据放入到数据库中(或是内存NOSQL系统中)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/327521.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用计算机远程关闭手机软件,如何使用手机远程遥控电脑关机?手机遥控电脑关机方法图文介绍...

电脑定时关机很正常&#xff0c;但是你试过手机遥控电脑关机吗&#xff1f;或许你有时候很懒&#xff0c;相关电脑如何通过手机遥控关机。现在已经可以实现&#xff0c;简单就可以遥控电脑关机。一个屌丝般的软件&#xff0c;高富帅般的技术&#xff0c;下边详细介绍一下如何使…

MyBatisPlus(笔记)

简介 学习MyBatis-Plus之前要先学MyBatis–>Spring—>SpringMVC 为什么要学它?MyBatisPlus可以节省我们大量的时间,所有CRUD代码都可以自动完成 JPA, tk-mapper ,MyBatisPlus 偷懒用的! 是什么? 官网:https://baomidou.com/ 特性 无侵入&#xff1a;只做增强不做…

WebAPi的可视化输出模式(RabbitMQ、消息补偿相关)——所有webapi似乎都缺失的一个功能

最近的工作我在做一个有关于消息发送和接受封装工作。大概流程是这样的&#xff0c;消息中间件是采用rabbitmq&#xff0c;为了保证消息的绝对无丢失&#xff0c;我们需要在发送和接受前对消息进行DB落地。在发送前我会先进行DB的插入&#xff0c;单表插入&#xff0c;所以在性…

java实现遍历树形菜单方法——Dao层

Dao层接口&#xff1a;/** * Title: IVoteTreeDao.java * Package org.dao * Description: TODO该方法的主要作用&#xff1a; * author A18ccms A18ccms_gmail_com * date 2017-5-6 下午10:38:47 * version V1.0 */ package org.dao;import java.util.List;import org.e…

文件损坏 无法删除 怎么使用chkdsk磁盘修复工具

有时候我们会遇到文件无法删除的问题&#xff0c;该如何解决。对于专业人士可能比较简单。对于小白&#xff0c;就够折腾人的了。下面分享下我是怎么做的。 很简单很实用。 现象&#xff1a;此时哪里有损坏&#xff0c;一般会在删除文件时&#xff0c;莫名的提示有文件无法删除…

35c3 krautflare

参考这篇文章可以彻底了解本题的漏洞所在 https://xz.aliyun.com/t/6527 由于Math.expm1经过patch以后的返回值不可能是-0&#xff0c;但是patch的地方是在typer优化中&#xff0c;所以实际上如果没有优化的话是可以返回-0的&#xff0c;这就意味着如果我们先不停地Math.expm1…

Java集合框架综述

转载自 Java集合框架综述 集合框架&#xff08;collections framework&#xff09; 首先要明确&#xff0c;集合代表了一组对象&#xff08;和数组一样&#xff0c;但数组长度不能变&#xff0c;而集合能&#xff09;。Java中的集合框架定义了一套规范&#xff0c;用来表示、…

vue项目没有启动成功的原因之一

删除mould。。。本地从新安装

RabbitMQ 高可用集群搭建及电商平台使用经验总结

面向EDA&#xff08;事件驱动架构&#xff09;的方式来设计你的消息AMQP routing key的设计RabbitMQ cluster搭建Mirror queue policy设置两个不错的RabbitMQ plugin 大型应用插件(Sharding、Rederation)Queue镜像失败手动同步各集群配置同步方式&#xff08;RabbitMQ export\i…

谷歌浏览器如何阻止弹窗广告?右下角弹窗一个接一个的弹出 每隔几分钟又来一波 怎么屏蔽?

谷歌浏览器如何阻止弹窗广告&#xff1f;右下角弹窗一个接一个的弹出 每隔几分钟又来一波 怎么屏蔽&#xff1f; 作者&#xff1a;知乎用户 链接&#xff1a;https://www.zhihu.com/question/319190736/answer/645314963 来源&#xff1a;知乎 著作权归作者所有。商业转载请联…

如何线程安全的使用HashMap

转载自 如何线程安全的使用HashMap 在周二面试时&#xff0c;一面的面试官有问到 HashMap 是否是线程安全的&#xff0c;如何在线程安全的前提下使用 HashMap,其实也就是 HashMap&#xff0c;Hashtable&#xff0c;ConcurrentHashMap 和 synchronized Map 的原理和区别。当时有…

用.net core 写后端—— c++外的另一种选择?

一、.net core简介 &#xff08;1&#xff09;.net是什么 .net实际是遵守同一个标准&#xff08;ECMA&#xff09;的多种不同实现&#xff0c;如.net Framework、Mono、和较新的.netcore。C#是.net支持的其中一种语言&#xff0c;理论上任何遵循公共语言规范&#xff08;CLS&am…

《微软开源跨平台移动开发实践》团购通知

【新书推荐】《微软开源跨平台移动开发实践》带你走近微软开源开源跨平台技术 大家的响应非常积极&#xff0c;接近400位同学想团购。 这两天通过作者李争的努力&#xff0c;为大家争取到了非常实惠的价格&#xff0c;投票结果看不到具体是谁参与了投票&#xff0c;请参与投票的…

Invalid character found in the request target. The valid characters are defi

解决Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 问题 ApiOperation(value "根据排污口类型获取所有企业排污口信息和经度和纬度", notes "获取所有企业排污口信息和经度和纬度") PostMappin…

大咖微课 | 直面Angular2系列课第二期开讲

1.背景介绍&#xff1a;Angular1.x与Angular2 近年来&#xff0c;Web 开发技术的发展日新月异&#xff0c;各种框架层出不穷。在这样的大背景之下&#xff0c;2010年10月&#xff0c;Google 首次发布了自己的 Web 开发框架&#xff0c;名为 AngularJS&#xff0c;也叫 Angular&…

HashMap在java并发中如何发生死循环

转载自 HashMap在java并发中如何发生死循环 在多线程环境中&#xff0c;使用HashMap进行put操作时会引起死循环&#xff0c;导致CPU使用接近100%&#xff0c;下面通过代码分析一下为什么会发生死循环。 首先先分析一下HashMap的数据结构&#xff1a;HashMap底层数据结构是有一…

计算机和影视结合专业,计算机专业专业建设总结与典型案例2.5微电影拍摄与后期制作(影视拍摄与后期制作技术)课....

计算机专业专业建设总结与典型案例2.5微电影拍摄与后期制作(影视拍摄与后期制作技术)课. (11页)本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01;9.9 积分微电影拍摄与后期制作(影视拍摄与后期制作技术)…

SpringBoot +Vue前后端分离(笔记)

前后端分离简介 前后端分离 前后端分离就是将⼀个应⽤的前端代码和后端代码分开写&#xff0c;为什么要这样做&#xff1f; 如果不使⽤前后端分离的⽅式&#xff0c;会有哪些问题&#xff1f; 传统的 Java Web 开发中&#xff0c;前端使⽤ JSP 开发&#xff0c;JSP 不是由后…

.NET Core下使用gRpc公开服务(SSL/TLS)

一、前言 前一阵子关于.NET的各大公众号都发表了关于gRpc的消息&#xff0c;而随之而来的就是一波关于.NET Core下如何使用的教程&#xff0c;但是在这众多的教程中基本都是泛泛而谈&#xff0c;难以实际在实际环境中使用&#xff0c;而该篇教程以gRpc为主&#xff0c;但是使用…

HashMap jdk1.7源码阅读与解析

转载自 HashMap源码阅读与解析 一、导入语 HashMap是我们最常见也是最长使用的数据结构之一&#xff0c;它的功能强大、用处广泛。而且也是面试常见的考查知识点。常见问题可能有HashMap存储结构是什么样的&#xff1f;HashMap如何放入键值对、如何获取键值对应的值以及如何…