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與線程安全


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM