并发编程之的ArrayList安全性的详细解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 并发编程之的ArrayList安全性的详细解析

ArrayList不安全

ArrayList中的add方法没有synchronized修饰,是不安全的

下面代码运行结果(异常 java.util.ConcurrentModificationException):



import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
 * @author zkw
 * @Description list不安全
 */
public class ThreadList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            }, i+"").start();
        }
    }
}
解决方法
  1. 使用Vector (已过时) 使用的是synchronized机制
  2. 使用Collections.synchronizedList()方法修饰ArrayList (性能不高)
    Collections中还有synchronizedMap和synchronizedSet的方法,可以修饰线程不安全的HashSet,HashMap
  3. 使用java.util.concurrent.CopyOnWriteArrayList(推荐)使用的是lock锁

使用CopyOnWriteArrayList

底层使用的是ReentrantLock可重用锁

下面给出CopyOnWriteArrayList 的 add源码

 

 final transient ReentrantLock lock = new ReentrantLock();    
    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#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();
        }
    }

案例运行结果:

案例源码:



import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
 * @author zkw
 * @Description list不安全
 */
public class ThreadList {
    public static void main(String[] args) {
        List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            }, i+"").start();
        }
    }
}

CopyOnWriteArrayList解析

CopyOnWriteArrayList 利用的是读写分离的思想,读和写的是不同的容器

底层使用的是一个Object数组,每次新添加元素的时候利用的是Arrays.copyOf来创建一个新数组达到扩容效果

使用的是ReentrantLock来保证线程安全

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

 

 final transient ReentrantLock lock = new ReentrantLock();  
    private transient volatile Object[] array;
    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#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); //将新容器设置为该list的容器
            return true;
        } finally {
            lock.unlock();
        }
    }


相关文章
|
4月前
|
安全 Java
java线程之List集合并发安全问题及解决方案
java线程之List集合并发安全问题及解决方案
559 1
|
4月前
|
缓存 安全 Java
全面解读ConcurrentHashMap:Java中的高效并发数据结构
全面解读ConcurrentHashMap:Java中的高效并发数据结构
1363 2
|
24天前
|
安全 Java 测试技术
掌握Java的并发编程:解锁高效代码的秘密
在Java的世界里,并发编程就像是一场精妙的舞蹈,需要精准的步伐和和谐的节奏。本文将带你走进Java并发的世界,从基础概念到高级技巧,一步步揭示如何编写高效、稳定的并发代码。让我们一起探索线程池的奥秘、同步机制的智慧,以及避免常见陷阱的策略。
|
3月前
|
存储 缓存 NoSQL
优化Java中网络通信的性能策略
优化Java中网络通信的性能策略
|
3月前
|
设计模式 并行计算 安全
Java面试题: 如何使用装饰器模式来增强ConcurrentHashMap的功能?在什么情况下应该使用CopyOnWriteArrayList而不是ArrayList?
Java面试题: 如何使用装饰器模式来增强ConcurrentHashMap的功能?在什么情况下应该使用CopyOnWriteArrayList而不是ArrayList?
27 0
|
3月前
|
存储 安全 Java
Java面试题:请解释Java内存模型,并说明如何在多线程环境下使用synchronized关键字实现同步,阐述ConcurrentHashMap与HashMap的区别,以及它如何在并发环境中提高性能
Java面试题:请解释Java内存模型,并说明如何在多线程环境下使用synchronized关键字实现同步,阐述ConcurrentHashMap与HashMap的区别,以及它如何在并发环境中提高性能
28 0
|
4月前
|
存储 安全 Java
深入解析Java HashMap的高性能扩容机制与树化优化
深入解析Java HashMap的高性能扩容机制与树化优化
127 1
|
5月前
|
安全 算法 Java
Java中的并发编程技术:解锁高效多线程应用的秘密
Java作为一种广泛应用的编程语言,其并发编程技术一直备受关注。本文将深入探讨Java中的并发编程,从基本概念到高级技巧,帮助读者更好地理解并发编程的本质,并学会如何在多线程环境中构建高效可靠的应用程序。
|
5月前
|
安全 容器
并发编程之的ArrayList安全性的详细解析
并发编程之的ArrayList安全性的详细解析
29 0
|
5月前
|
安全 算法 Java
Java中的多线程编程及其优化策略
【2月更文挑战第9天】在当今高度并发的技术环境下,多线程编程成为了Java开发中不可忽视的一部分。本文将介绍Java中多线程编程的基本概念和核心特性,并深入探讨如何优化多线程程序以提高性能和稳定性。