ArrayList 线程安全问题及解决方案

前言

在提到多线程的时候我们大都会想到ArrayList 与 HashMap,这两个类型都是非线性安全的!在多个线程同时操作改集合对象时,会出现哪些问题呢?在传统的集合包内的集合类到底为什么线程非安全呢?在新的JUC包类又有什么可以替代呢? 

介绍

①为什么ArrayList 是线性不安全的?

②替代措施及解决方案?

ArrayList 我们都知道底层是以数组方式实现的,实现了可变大小的数组,它允许所有元素,包括null。看下面一个例子:开启多个线程操作List集合,向ArrayList中增加元素,同时去除元素。

import java.util.ArrayList;    
import java.util.Collections;    
import java.util.List;    
import java.util.Vector;    
    
public class ListTest {    
    // ArrayList    
    protected static ArrayList<Object> arrayList = new ArrayList<Object>();    
    
    // 解决措施①:使用Vector集合    
    protected static Vector<Object> arrayListSafe1 = new Vector<Object>();    
    
    // 解决措施②:我们加上Collections.synchronizedList,它会自动将我们的list方法进行改变,最后返回给我们一个加锁了List    
    static List<Object> arrayListSafe2 = Collections.synchronizedList(new ArrayList<Object>());    
    
    public static void main(String[] args) {    
        Thread[] threads = new Thread[500];    
        for (int i = 0; i < threads.length; i++) {    
            threads[i] = new ArrayListThread();    
            threads[i].start();    
        }    
    
        for (int i = 0; i < threads.length; i++) {    
            try {    
                threads[i].join();// 等待该线程终止    
            } catch (InterruptedException e) {    
                e.printStackTrace();    
            }    
        }    
        // 输出list中的对象元素    
        for (int i = 0; i < threads.length; i++) {    
            System.out.println(arrayList.get(i));    
        }    
    }    
}    
    
/**  
 * 线程类,执行arrayList的add()增加方法  
 *   
 * @author zyx  
 *  
 */    
class ArrayListThread extends Thread {    
    
    @Override    
    public void run() {    
        try {    
            Thread.sleep(1000);    
        } catch (InterruptedException e) {    
            e.printStackTrace();    
        }    
        // 增加元素    
        ListTest.arrayList.add(Thread.currentThread().getName());    
    }    
    
}   
View Code

运行代码结果可知,会出现以下几种情况:

①Null

②某些线程并未打印

③数组下标越界异常

由此我们可以得出,在多线程情况下操作ArrayList 并不是线性安全的。那如何解决呢?

第一种方案:

使用Vertor集合

protected static Vector<Object> arrayListSafe1 = new Vector<Object>();  
View Code

第二种方案:

使用Collections.synchronizedList。它会自动将我们的list方法进行改变,最后返回给我们一个加锁了List

protected static List<Object> arrayListSafe2 = Collections.synchronizedList(new ArrayList<Object>());   
View Code

第三种方案:

使用JUC中的CopyOnWriteArrayList类进行替换。具体详情可参考JUC框架

常见集合线性是否安全可参考下图:

List.png

 

参考文章:

ArrayList线程不安全详解

Java中 Vector的使用详解

Set、List、Map线程安全问题

Set与线程安全

posted on 2019-07-08 23:24  Zhou先森  阅读(24766)  评论(0编辑  收藏  举报

导航