Java進階技術第五章——高並發之同步容器__JAVA進階編程系列

來源:互聯網
上載者:User
前言

前言點擊此處查看:
http://blog.csdn.net/wang7807564/article/details/79113195 同步容器

問題引出:

有N張火車票,每張票都有一個編號,同時有10個視窗對外售票,寫一個類比程式。

public class TicketSeller {        static List<String> tickets = new ArrayList<>();        static {                for(int i=0; i<10000; i++) tickets.add("票編號:" + i);        }        public static void main(String[] args) {                for(int i=0; i<10; i++) {                        new Thread(()->{                                while(tickets.size() > 0) {                                        System.out.println("銷售了--" + tickets.remove(0));                                }                        }).start();                }        }}

在上述程式運行中,會報錯,數組越界:

java.lang.ArrayIndexOutOfBoundsException

很顯然,這是因為多線程之間沒有處理好同步問題造成的。 Vector

嘗試將tickets換為vector類型:

static Vector<String> tickets = new Vector<>();

List介面一共有三個實作類別,分別是ArrayList、Vector和LinkedList.
Vector與ArrayList一樣,也是通過數組實現的,不同的是它支援線程的同步,即某一時刻只有一個線程能夠寫Vector,避免多線程同時寫而引起的不一致性。它的內部是使用synchronized關鍵字來實現同步鎖的。
雖然在筆者測試中沒有沒有出現過數組越界的問題,但是使用Vector是具有潛在的線程不安全風險的。原因是vector對每個讀取和寫入的方法是單獨加鎖的,也就是說使用synchronized關鍵字修飾了讀取和寫入的方法。但是在上面的例子中,讀取和寫入應該作為一個整體,這個整體應該保證原子性,單獨的讀取和寫入雖然加鎖,但是這個整體仍然是線程不安全的,這個整體對應的就是while迴圈的代碼塊。如果想要實現絕對的安全執行緒,可以改成如下例子,但是是犧牲效能的:

            new Thread(()-> {                synchronized (new Object()) {                    {                        while (tickets.size() > 0) {                            System.out.println("銷售了--" + tickets.remove(0));                        }                    }                }            }).start();
Collections.synchronizedXXX():

Collections類是一個工廠類,通過這個工廠類來擷取一些同步容器的執行個體。
這些通過Factory 方法擷取到的執行個體,內部也是通過synchronized關鍵字來完成同步的。
Synchronizedxxx方法有兩個不足:
1. 首先,這種方法對於延展性是一種障礙,因為一次只能有一個線程可以訪問hash表。
2. 同時,這樣仍不足以提供真正的執行緒安全性,許多公用的混合操作仍然需要額外的同步。

使用下面的代碼,也能達到解決該問題的目的:

static List<String> tickets = Collections.synchronizedList(new ArrayList<>());

在擷取tickects執行個體的時候,使用collections.synchronizedxxx()函數進行同步,這樣可以擷取一個同步容器的執行個體。避免了數組越界問題。
對於上述問題,如果使用synchronized關鍵字也可以實現:

While(true)Synchronized(tickets){判斷sizeRemove()移除}

這裡面相當於將size()和remove()兩個原子操作合并為一個原子操作,實現了讀寫鎖。但是,這種方法相對來說,更佔用CPU資源。

雖然諸如get()和put()之類的簡單操作可以在不需要額外同步的情況下安全地完成.但還是有一些公用的操作序列,例如迭代操作或者put-if-absent(空則放入),需要外部的同步,以避免資料爭用。
synchronizedMap、synchronizedList等也被稱為有條件的安全執行緒同步的集合封裝器:
  也就是說所有單個的操作都是安全執行緒的.但是多個操作組成的操作序列卻可能導致資料爭用,因為在操作序列中控制流程取決於前面操作的結果。
  所以,在JDK 5版本以後,對於高並發情境推薦使用ConcurrentHashMap.其特點:效率比Hashtable高,並發性比hashmap好,HashMap中未進行同步考慮,而Hashtable則使用了synchronized,帶來的直接影響就是可選擇,我們可以在單線程時使用HashMap提高效率,而多線程時用Hashtable來保證安全,而ConcurrentHashMap則結合了兩者的特點。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.