java 線程 同步類容器和并發(fā)類容器

  • 同步類容器都是線程安全的,比如Vector,HashTable,這些容器的同步功能其實是由Collections.Synchronized.**等工廠方法去創(chuàng)建實現(xiàn)的,底層機(jī)制無非是用傳統(tǒng)的synchronized關(guān)鍵字給每個公共方法進(jìn)行同步,使得容器再同一時間只有一個線程訪問,這些古老的同步類容器已經(jīng)有點不適應(yīng)當(dāng)今的高并發(fā)互聯(lián)網(wǎng)需求
  • 某些場景下可能要加鎖來保護(hù)復(fù)合類操作,復(fù)合類操作,比如:迭代,跳轉(zhuǎn)(按指定順序查找當(dāng)前元素的下一元素),以及條件運算,這些復(fù)合操作在多線程并發(fā)的修改容器時,可能會出現(xiàn)意外的行為,比如ConcurrentModificationExcepiton,當(dāng)容器迭代的過程中,被其他線程并發(fā)的修改了內(nèi)容,這是因為早期設(shè)計迭代器的時候,并沒有考慮到并發(fā)修改的問題
  • 單獨的并發(fā)修改,比如remove還是線程安全的:
public class Tickets {

    public static void main(String[] args) {
        //初始化火車票池并添加火車票:避免線程同步可采用Vector替代ArrayList  HashTable替代HashMap
        
        final Vector<String> tickets = new Vector<String>();
        // 被Collections.synchronized**處理之后,map現(xiàn)在是線程安全的
        //Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());

        for(int i = 1; i<= 1000; i++){
            tickets.add("火車票"+i);
        }
        
//      for (Iterator iterator = tickets.iterator(); iterator.hasNext();) {
//          String string = (String) iterator.next();
//          tickets.remove(20);
//      }
        //單獨的并發(fā)修改,比如remove還是線程安全的 ,remov并不是復(fù)合類操作
        for(int i = 1; i <=10; i ++){
            new Thread("線程"+i){
                public void run(){
                    while(true){
                        if(tickets.isEmpty()) break;
                        System.out.println(Thread.currentThread().getName() + "---" + tickets.remove(0));
                    }
                }
            }.start();
        }
    }
}

  • jdk5.0之后提供多種并發(fā)類容器來替代同步類容器來提高從而改善性能,同步類容器都是串行化的,多線程環(huán)境時,嚴(yán)重降低應(yīng)用程序的吞吐量

    • ConcurrentMap容器

      • ConcurrentHashMap
        對應(yīng)的非并發(fā)容器:HashMap
        目標(biāo):代替Hashtable、synchronizedMap,支持復(fù)合操作
        原理:JDK6中采用一種更加細(xì)粒度的加鎖機(jī)制Segment“分段鎖”,減小鎖的粒度,JDK8中采用CAS無鎖算法,詳細(xì)分析推薦閱讀[【JDK】:ConcurrentHashMap高并發(fā)機(jī)制——【轉(zhuǎn)載】(http://blog.csdn.net/u011080472/article/details/51392712)。

      • ConcurrentSkipListMap
        對應(yīng)的非并發(fā)容器:TreeMap
        目標(biāo):代替synchronizedSortedMap(TreeMap)
        原理:Skip list(跳表)是一種可以代替平衡樹的數(shù)據(jù)結(jié)構(gòu),默認(rèn)是按照Key值升序的。Skip list讓已排序的數(shù)據(jù)分布在多層鏈表中,以0-1隨機(jī)數(shù)決定一個數(shù)據(jù)的向上攀升與否,通過”空間來換取時間”的一個算法。ConcurrentSkipListMap提供了一種線程安全的并發(fā)訪問的排序映射表。內(nèi)部是SkipList(跳表)結(jié)構(gòu)實現(xiàn),在理論上能夠在O(log(n))時間內(nèi)完成查找、插入、刪除操作。

    • CopyOnWrite容器,讀寫分離思想,適用于讀多寫少的場景,如果寫多的話,可以使用synchronized鎖

      • CopyOnWriteArrayList
        對應(yīng)的非并發(fā)容器:ArrayList
        目標(biāo):代替Vector、synchronizedList
        原理:利用高并發(fā)往往是讀多寫少的特性,對讀操作不加鎖,對寫操作,先復(fù)制一份新的集合,在新的集合上面修改,然后將新集合賦值給舊的引用,并通過volatile 保證其可見性,當(dāng)然寫操作的鎖是必不可少的了。關(guān)于這一部分可參考【JDK】:CopyOnWriteArrayList、CopyOnWriteArraySet 源碼解析
      • CopyOnWriteArraySet
        對應(yīng)的費并發(fā)容器:HashSet
        目標(biāo):代替synchronizedSet
        原理:基于CopyOnWriteArrayList實現(xiàn),其唯一的不同是在add時調(diào)用的是CopyOnWriteArrayList的addIfAbsent方法,其遍歷當(dāng)前Object數(shù)組,如Object數(shù)組中已有了當(dāng)前元素,則直接返回,如果沒有則放入Object數(shù)組的尾部,并返回。
        關(guān)于這一部分可參考【JDK】:CopyOnWriteArrayList、CopyOnWriteArraySet 源碼解析
    • 有序set

      • ConcurrentSkipListSet
        對應(yīng)的非并發(fā)容器:TreeSet
        目標(biāo):代替synchronizedSortedSet
        原理:內(nèi)部基于ConcurrentSkipListMap實現(xiàn)
    • 隊列

      • ConcurrentLinkedQueue,高并發(fā)無界隊列,不允許null
        不會阻塞的隊列
        對應(yīng)的非并發(fā)容器:Queue
        原理:基于鏈表實現(xiàn)的FIFO隊列(LinkedList的并發(fā)版本)
        add()和offer()都是添加元素,在此queue中沒有任何區(qū)別
        poll()和peek()都是取第一個元素,前者會刪除元素,后者不會

      • LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue,阻塞隊列
        對應(yīng)的非并發(fā)容器:BlockingQueue
        特點:拓展了Queue,增加了可阻塞的插入和獲取等操作
        原理:通過ReentrantLock實現(xiàn)線程安全,通過Condition實現(xiàn)阻塞和喚醒
        實現(xiàn)類:
        LinkedBlockingQueue:基于鏈表實現(xiàn)的可阻塞的FIFO隊列,無界隊列
        ArrayBlockingQueue:基于數(shù)組實現(xiàn)的可阻塞的FIFO隊列,有界隊列
        PriorityBlockingQueue:按優(yōu)先級排序的隊列,元素必須實現(xiàn)comparable接口,判斷優(yōu)先級,無界隊列,注意循環(huán)或者迭代該queue的時候,表現(xiàn)形式并不是優(yōu)先級從高到底,而是執(zhí)行take方法的時候,執(zhí)行compare方法,有點懶加載的意思
        SynchronousQueue:沒有沒有緩沖的隊列,Java 6的并發(fā)編程包中的SynchronousQueue是一個沒有數(shù)據(jù)緩沖的BlockingQueue,生產(chǎn)者線程對其的插入操作put必須等待消費者的移除操作take,反過來也一樣。不像ArrayBlockingQueue或LinkedListBlockingQueue,SynchronousQueue內(nèi)部并沒有數(shù)據(jù)緩存空間,你不能調(diào)用peek()方法來看隊列中是否有數(shù)據(jù)元素,因為數(shù)據(jù)元素只有當(dāng)你試著取走的時候才可能存在,不取走而只想偷窺一下是不行的,當(dāng)然遍歷這個隊列的操作也是不允許的。隊列頭元素是第一個排隊要插入數(shù)據(jù)的線程,而不是要交換的數(shù)據(jù)。數(shù)據(jù)是在配對的生產(chǎn)者和消費者線程之間直接傳遞的,并不會將數(shù)據(jù)緩沖數(shù)據(jù)到隊列中??梢赃@樣來理解:生產(chǎn)者和消費者互相等待對方,握手,然后一起離開。先有take,后有add。
        DelayQueue:帶有延遲時間的queue,當(dāng)延遲時間到了的時候,才能從隊列里toke到該元素,必須實現(xiàn)Delayed接口,無界隊列,

    • Deque 雙端隊列(double ended queue)

      • LinkedBlockingDeque:線程安全的雙端隊列實現(xiàn),并未實現(xiàn)讀寫分離,同一時間只能有一個線程對其進(jìn)行操作,在高并發(fā)應(yīng)用場景中性能要低于其他阻塞隊列。
  • 并發(fā)容器代碼示例

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class UseConcurrentMap {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Object> chm = new ConcurrentHashMap<String, Object>();
        chm.put("k1", "v1");
        chm.put("k2", "v2");
        chm.put("k3", "v3");
                //如果key不存在則添加
        chm.putIfAbsent("k4", "vvvv");
        //System.out.println(chm.get("k2"));
        //System.out.println(chm.size());
        
        for(Map.Entry<String, Object> me : chm.entrySet()){
            System.out.println("key:" + me.getKey() + ",value:" + me.getValue());
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來是分開三篇的,后來想想還是整...
    coder_pig閱讀 1,780評論 2 17
  • 一.線程安全性 線程安全是建立在對于對象狀態(tài)訪問操作進(jìn)行管理,特別是對共享的與可變的狀態(tài)的訪問 解釋下上面的話: ...
    黃大大吃不胖閱讀 972評論 0 3
  • 晚間,我對姐說:我給媽訂了一個新手機(jī)啊,跟我的手機(jī)同個牌子的,智能機(jī)。 姐:買新的干啥? 我:因為老年機(jī)快壞了,媽...
    舒云心閱讀 727評論 2 50
  • 能帶給你多少新鮮感 小學(xué)門口,一塊五的熱狗,微辣加番茄醬 非常廉價的味道,卻很懷念。
    游離因子閱讀 241評論 0 0
  • 四十來歲的你: 你好啊。 現(xiàn)在看到這封信的你,如果遵循了社會規(guī)律的話,應(yīng)該是一個公司的員工,一個男人的妻子和一個(...
    山海不可平_zyx閱讀 4,893評論 0 0

友情鏈接更多精彩內(nèi)容