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,一经查实,立即删除!

相关文章

java实现遍历树形菜单方法——映射文件VoteTree.hbm.xml

<?xml version"1.0" encoding"utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Mapping file au…

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

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

MyBatisPlus(笔记)

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

Java多线程:线程安全和非线程安全的集合对象

转载自 Java多线程&#xff1a;线程安全和非线程安全的集合对象 一、概念&#xff1a; 线程安全&#xff1a;就是当多线程访问时&#xff0c;采用了加锁的机制&#xff1b;即当一个线程访问该类的某个数据时&#xff0c;会对这个数据进行保护&#xff0c;其他线程不能对其访问…

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;莫名的提示有文件无法删除…

计算机网络产生的历史背景,网络技术背景及sdn概述.pdf

网络技术背景及sdn概述软件定义网络黄韬北京邮电大学北京邮电大学第1章&#xff1a;背景与概述个人简介个人简介• 黄韬– 信息与通信工程学院– 博士&#xff0c;副教授– 科研方向科研方向&#xff1a;&#xff1a;未来网络未来网络– 教学课程&#xff1a;计算机网络、软件定…

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…

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

Service接口&#xff1a; /** * Title: IVoteTreeService.java * Package org.Service * Description: TODO该方法的主要作用&#xff1a; * author A18ccms A18ccms_gmail_com * date 2017-5-6 下午10:42:10 * version V1.0 */ package org.Service;import java.util.Li…

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

谷歌浏览器如何阻止弹窗广告&#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 的原理和区别。当时有…

脚本可以放在html外,关于把script脚本放在html结束标签外的运行结果???

杨__羊羊在哪里放置 JavaScript 代码&#xff1f;通常情况下&#xff0c;JavaScript 代码是和 HTML 代码一起使用的&#xff0c;可以将 JavaScript 代码放置在 HTML 文档的任何地方。但放置的地方&#xff0c;会对 JavaScript 代码的正常执行会有一定影响&#xff0c;具体如下所…

后端解决跨域问题---SpringBoot

解决跨域问题 在后端解决跨域问题&#xff1a; 新建配置类 config/ CrosConfig.java /*** 解决跨域问题*/ Configuration public class CrosConfig implements WebMvcConfigurer {Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/*…

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

/** * Title: HibernateUtil.java * Package org.web * Description: TODO该方法的主要作用&#xff1a; * author A18ccms A18ccms_gmail_com * date 2017-5-6 下午1:41:30 * version V1.0 */ package org.util;import org.hibernate.Session; import org.hibernate.cfg…

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

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

16-就业课(2.1)-应用容器-Docker

https://www.jianshu.com/writer#/notebooks/46975630/notes/74245796 01-今日内容.mp4 02-初始docker-docker概述.mp4 03-初始docker-docker安装.mp4 04-初始docker-docker架构.mp4 05-初始docker-配置镜像加速器.mp4 https://www.jianshu.com/writer#/notebooks/4697563…