天天看點

多線程——并發容器類——Vector(同步容器)HashTable(同步),同步類容器的線程安全使用

1.容器的概述:

ConcurrentMap集合類使用與底層原理分析				
CopyOnWrite集合類使用與底層原理分析					
并發與阻塞隊列Queue講解							
模拟阻塞隊列實戰	
ArrayBlockingQueue
ConcurrentLinkedQueue
SynchronousQueue
PriorityBlockingQueue優先級隊列
DelayQueue延遲隊列應用與實戰	
           

2.同步類容器的問題

同步類容器的狀态都是串行化的。(100個請求,隻有一個請求執行,執行後釋放鎖其他請求才能執行)

ConcurrentModificationException并發修改導緻的目前線程更改異常

這些容器的同步功能其實都是有JDK的Collections.synchronized***等工廠方法去建立實作的。

同步類容器都是線程安全的,但在某些場景下可能需要加鎖來保護複合操作。
    複合類操作如:疊代(反複通路元素,周遊完容器中所有的元素)、跳轉(根
據指定的順序找到目前元素的下一個元素)、以及條件運算。
    這些複合操作在多線程并發地修改容器時,可能會表現出意外的行為,最經典
的便是ConcurrentModificationException,原因是當容器疊代的過程中,被
并發的修改了内容,這是由于早期疊代器設計的時候并沒有考慮并發修改的問題
           

3.同步類容器的使用

        Vector、HashTable

同步類容器:
如Vector、HashTable。
    這些容器的同步功能其實都是有JDK的Collections.synchronized***等
工廠方法去建立實作的。
    其底層的機制無非就是用synchronized關鍵字對每個公用的方法都進行同
步,或者使用Object mutex對象鎖的機制使得每次隻能有一個線程通路容
器的狀态。
           

 在一個同步類容器集合中,删除某個指定元素:m1();m2()方法會報異常ConcurrentModificationException。而m3()方法成功

package com.bfxy.thread.core.collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;

public class UseSyncCollection {

    // 出現java.util.ConcurrentModificationException
    public Collection<String> m1(Vector<String> list) {
        for (String temp : list) {
            if ("3".equals(temp)) {
                list.remove(temp);
            }
        }
        return list;

    }
    // 出現java.util.ConcurrentModificationException
    public Collection<String> m2(Vector<String> list) {
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String temp = iterator.next();
            if ("3".equals(temp)) {
                list.remove(temp);
            }
        }
        return list;

    }
    //successful!
    public Collection<String> m3(Vector<String> list) {
        for (int i = 0; i < list.size(); i++) {
            if ("3".equals(list.get(i))) {
                list.remove(i);
            }
        }
        return list;
    }


    public static void main(String[] args) {

    	Vector v = new Vector<>();
    	v.add("1");
    	v.add("2");
    	v.add("3");
    	UseSyncCollection test = new UseSyncCollection();
//		Collection<String> ret1 = test.m1(v);
//		System.err.println(ret1.toString());

//        Collection<String> ret2 = test.m2(v);
//        System.err.println(ret2.toString());

        Collection<String> ret3 = test.m1(v);
        System.err.println(ret3.toString());


//        List<String> list = new ArrayList<>();
//        Collections.synchronizedCollection(list);

    }
}
           

Vector(同步)方法大多用synchronized修飾與List(非同步)都能夠使用方法3操作成功。

增強for循環以及遊标循環對集合容器的資料操作不是一個線程在操作,簡單for循環是單個線程操作

4.同步容器的實作:

1.其底層的機制無非就是用synchronized關鍵字對每個公用的方法都進行同步,

2.或者使用Object mutex對象鎖的機制使得每次隻能有一個線程通路容器的狀态。

ConcurrentModificationException并發修改導緻的目前線程更改異常

這些容器的同步功能其實都是有JDK的Collections.synchronized***等工廠方法去建立實作的。

//        List<String> list = new ArrayList<>();
//        Collections.synchronizedCollection(list);
           

這樣就把List變成同步容器了,實作線程安全了:方法中會建立

new SynchronizedCollection(list);    
           

然後:SynchronizedCollection對象中有參數final Object mutex;(對象鎖)

duilist操作時候都是對對象鎖操作如:

public int size() {
            synchronized (mutex) {return c.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return c.isEmpty();}
        }
        public boolean contains(Object o) {
            synchronized (mutex) {return c.contains(o);}
        }
        public Object[] toArray() {
            synchronized (mutex) {return c.toArray();}
        }
        public <T> T[] toArray(T[] a) {
            synchronized (mutex) {return c.toArray(a);}
        }
           

總結原理:會将list變成對象SynchronizedCollection;然後對list操作時候,會受到SynchronizedCollection對象中,mutex對象進行鎖處理

繼續閱讀