1. 程式人生 > >【Java 高併發】併發下的ArrayList&&HashMap

【Java 高併發】併發下的ArrayList&&HashMap



    在平常的java程式碼開發過程中,我們會經常性的就會用到ArrayListHashMap來輔助自己完成需求工作,而且配合的也是相當的默契。但是如果環境發生改變,在併發情況下,他是否還能夠順利的完成我們想要的要求呢??

併發下的ArrayList:

其實對於ArrayList而言,他並非是一個執行緒安全的容器,如果在多執行緒環境下使用ArrayList,必然會導致程式出錯。

public class ArrayListMultiThread {
    //    ArrayList-執行緒不安全 
    static ArrayList<Integer> a1 = new ArrayList<>(10);
    public static class AddThread implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 1000000; i++) {
                a1.add(i);
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
//        建立兩個執行緒t1,t2
        Thread t1 = new Thread(new AddThread());
        Thread t2 = new Thread(new AddThread());
//        兩個執行緒執行
        t1.start();
        t2.start();
//        保持順序輸出
        t1.join();
        t2.join();
        System.out.println(a1.size());
    }
}

    t1,t2兩個執行緒同時向ArrayList中新增容器,我們期望的效果肯定是2000000.但是由於執行緒不安全,它真的會得到我們想要的結果嗎?

情況一:由於ArrayList在擴容的過程中,內部一致性遭到了破壞,但是卻沒有任何工作去處理,沒有得到鎖的保護,使其另外一個執行緒看到了這樣的局面,進而出現了越界的問題。最後的結果則出現了異常的情況。

情況二:兩個執行緒同時訪問,發生了肢體上的衝突,對容器的同一位置進行了同時刻的賦值,整體下來則出現了不一致的畫面:

情況三:當然也有可能輸出2000000,得到我們想要的結果。每次都吵架,也會有和睦相處的時候啊!真心不易。縱然有時候能夠得到我們想要的結果的,但這也並非是我們想要的結果,唯一的解決方案就是更換一個“容器”,能夠達到兩者的永久性和睦相處,這樣問題不就解決了。我們採取更換的容器為:Vector

 static Vector<Integer> a1 = new Vector<>(10);


併發下的HashMap:

HashMap相比ArrayList而言,也是執行緒不安全的。待我們看程式碼細細分析:

   //    定義一個HashMap集合
    static Map<String, String> map = new HashMap<>();
    public static class AddThread implements Runnable {
        int start = 0;
        public AddThread(int start) {
            this.start = start;
        }
        @Override
        public void run() {
//            對i進行+2操作
            for (int i = start; i < 100000; i += 2) {
//                賦值以2為底的無符號整數
                map.put(Integer.toString(i), Integer.toBinaryString(i));
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
//        建立兩個執行緒t1,t2
        Thread t1 = new Thread(new HashMapMultiThread.AddThread(0));
        Thread t2 = new Thread(new HashMapMultiThread.AddThread(1));
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(map.size());
    }

執行到底會出什麼錯誤?我們可以通過jstack工具來輔助檢視。

    在命令視窗輸入"jps",可以查閱所有的java程序,我們根據程序號,通過"jstack +"程序號""對其某個程序進行詳細的檢視:

為了避免程序不安全,在併發的情況下,我們可以使用ConcurrentHashMap來代替HashMap工作。

static Map<String, String> map = new ConcurrentHashMap<>();

    在併發的環境下,其實有些操作都是可以避免的,比如一些執行緒不安全我們完全可以用執行緒安全的去取代其進行工作。