Collection线程不安全的举例

前言

1、当我们执行下面语句的时候,底层进行了什么操作

new ArrayList();

底层创建了一个空的数组,伴随着初始值为10

当执行add方法后,如果超过了10,那么会进行扩容,扩容的大小为原值的一半,也就是5个,使用下列方法扩容

Arrays.copyOf(elementData, netCapacity)

单线程环境下

单线程环境的ArrayList是不会有问题的

public class ArrayListNotSafeDemo {

public static void main(String[] args) {

Listlist = new ArrayList<>();

list.add("a");

list.add("b");

list.add("c");

for(String element : list) {

System.out.println(element);

}

}

}

多线程环境

为什么ArrayList是线程不安全的?因为在进行写操作的时候,方法上为了保证并发性,是没有添加synchronized修饰,所以并发写的时候,就会出现问题

当我们同时启动30个线程去操作List的时候

/**

* 集合类线程不安全举例

* @author: 陌溪

* @create: 2020-03-12-20:15

*/

public class ArrayListNotSafeDemo {

public static void main(String[] args) {

Listlist = new ArrayList<>();

for (int i = 0; i < 30; i++) {

new Thread(() -> {

list.add(UUID.randomUUID().toString().substring(0, 8));

System.out.println(list);

}, String.valueOf(i)).start();

}

}

}

这个时候出现了错误,也就是java.util.ConcurrentModificationException

这个异常是 并发修改的异常

解决方案

方案一:Vector

第一种方法,就是不用ArrayList这种不安全的List实现类,而采用Vector,线程安全的

关于Vector如何实现线程安全的,而是在方法上加了锁,即synchronized

这样就每次只能够一个线程进行操作,所以不会出现线程不安全的问题,但是因为加锁了,导致并发性基于下降

方案二:Collections.synchronized()

Listlist = Collections.synchronizedList(new ArrayList<>());

采用Collections集合工具类,在ArrayList外面包装一层 同步 机制

方案三:采用JUC里面的方法

CopyOnWriteArrayList:写时复制,主要是一种读写分离的思想

写时复制,CopyOnWrite容器即写时复制的容器,往一个容器中添加元素的时候,不直接往当前容器Object[]添加,而是先将Object[]进行copy,复制出一个新的容器object[] newElements,然后新的容器Object[] newElements里添加原始,添加元素完后,在将原容器的引用指向新的容器 setArray(newElements);这样做的好处是可以对copyOnWrite容器进行并发的度,而不需要加锁,因为当前容器不需要添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器

就是写的时候,把ArrayList扩容一个出来,然后把值填写上去,在通知其他的线程,ArrayList的引用指向扩容后的

查看底层add方法源码

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();

}

}

首先需要加锁

final ReentrantLock lock = this.lock;

lock.lock();

然后在末尾扩容一个单位

Object[] elements = getArray();

int len = elements.length;

Object[] newElements = Arrays.copyOf(elements, len + 1);

然后在把扩容后的空间,填写上需要add的内容

newElements[len] = e;

最后把内容set到Array中

HashSet线程不安全

CopyOnWriteArraySet

底层还是使用CopyOnWriteArrayList进行实例化

HashSet底层结构

同理HashSet的底层结构就是HashMap

但是为什么我调用 HashSet.add()的方法,只需要传递一个元素,而HashMap是需要传递key-value键值对?

首先我们查看hashSet的add方法

public boolean add(E e) {

return map.put(e, PRESENT)==null;

}

我们能发现但我们调用add的时候,存储一个值进入map中,只是作为key进行存储,而value存储的是一个Object类型的常量,也就是说HashSet只关心key,而不关心value

HashMap线程不安全

同理HashMap在多线程环境下,也是不安全的

public static void main(String[] args) {

Mapmap = new HashMap<>();

for (int i = 0; i < 30; i++) {

new Thread(() -> {

map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));

System.out.println(map);

}, String.valueOf(i)).start();

}

}

解决方法

1、使用Collections.synchronizedMap(new HashMap<>());

2、使用 ConcurrentHashMap

Mapmap = new ConcurrentHashMap<>();

java juc作者_Java面试之JUC系列:Collection线程不安全的举例相关推荐

  1. java面试常考_JAVA面试常考系列十

    JAVA面试常考系列十 题目一 Servlet是什么? Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,是用Java编写的服务器端程序,主要的 ...

  2. java arraylist 初始化_Java面试整理-基础篇8.集合1

    1.Java中常见的集合及其关系? 2.ArrayList.LinkedList.Vector的区别? 1. LinkedList.ArrayList.Vector都是List接口的子类:Linked ...

  3. 线程 sleep 取消_Java面试集锦:25道线程类相关面试题与答案(下)

    26. 并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对 ...

  4. java 取余_JAVA面试解析(有赞)

    一面引言 说在前面的话: 本文适合人群:急等着换工作的人 我承认刷面试题很有用的,纵观几年来的JAVA面试题,你会发现每家都差不多.比如,你仔细观察,你会发现,HashMap的出现几率未免也太高了吧! ...

  5. java lock 对象_Java并发编程锁系列之ReentrantLock对象总结

    Java并发编程锁系列之ReentrantLock对象总结 在Java并发编程中,根据不同维度来区分锁的话,锁可以分为十五种.ReentranckLock就是其中的多个分类. 本文主要内容:重入锁理解 ...

  6. java 模块 分工_Java秒杀系统实战系列~构建SpringBoot多模块项目

    摘要:本篇博文是"Java秒杀系统实战系列文章"的第二篇,主要分享介绍如何采用IDEA,基于SpringBoot+SpringMVC+Mybatis+分布式中间件构建一个多模块的项 ...

  7. java自我介绍_JAVA面试技巧之自我介绍

    [如何进行自我介绍] 自我介绍这个问题,不用多说了,面试必定会问!如果想要在自我介绍的时候就能够打动面试官,吸引面试官对我们的兴趣,那么像我们这种接受过Java培训的程序员的自我介绍当然不能和应届生或 ...

  8. java笔试题_Java面试才到笔试就没有然后了?快来签收,高频笔试57题及解答

    前言 很多人面试之前,可能没有在互联网公司工作过或者说工作过但年头较短,不知道互联网公司技术面试都会问哪些问题? 再加上可能自己准备也不充分,去面试没几个回合就被面试官几个问题打蒙了,甚至笔试都过不了 ...

  9. java基本特性_Java面试总结之Java基础

    无论是工作多年的高级开发人员还是刚入职场的新人,在换工作面试的过程中,Java基础是必不可少的面试题之一.能不能顺利通过面试,拿到自己理想的offer,在准备面试的过程中,Java基础也是很关键的.对 ...

最新文章

  1. CUDA Samples: Calculate Histogram(atomicAdd)
  2. 201671010417 金振兴 词频统计软件项目报告
  3. 创建ContentProvider的详细步骤
  4. mqtt协议视频教程_MQTT协议教程
  5. Tomcat 6.0 日志处理
  6. java实现linkstring,【JAVA SE基础篇】32.String类入门
  7. SolrCloud zookeeper节点信息
  8. ThreadPoolExcutor 线程池 异常处理 (上篇)
  9. 只可顺守不可逆取书法_闲章不“闲”
  10. 数据结构之基于Java的链接栈实现
  11. Flutter游戏:简单规则与结束页
  12. Centos7部署轻量级自动化运维工具pssh (亲测)
  13. 如何排查Oracle表空间不足问题
  14. 信息技术 用计算机做科学实验报告,8.用计算机做科学实验.doc
  15. 国开计算机实操题操作,国开大学计算机实操答案一.
  16. Amoeba:开源的分布式数据库Porxy解决方案
  17. rtthread spiflash (w25q64)
  18. 怎么制作鸿蒙系统启动盘,开物成务,鸿蒙操作系统全景解构
  19. 毕设第三周(12月19日——12月25日)
  20. 使用Python调用mdx字典文件进行查词

热门文章

  1. c语言电脑报价系统,笔记本电脑销售管理系统-C语言-课程设计-实验.doc
  2. 压缩 : tar . giz
  3. 《乌合之众》--Agree with something
  4. azure mysql 配置,php-在Azure云服务上配置WordPress以通过SSL连接到Azure MySQL
  5. 好用的影音APP要关注哪些方面和功能?
  6. 20171025-迷恋小概率事件
  7. python学习记录1(基础知识)
  8. 过了这么多年,我终于学会跟Office说再见
  9. error: expected constructor, destructor, or type conversion before ‘(’ token PLUGINLIB_DECLARE_CLAS
  10. ——————猿小王日记——————