1. 程式人生 > >Java併發(三)ConcurrentHashMap鎖分段機制

Java併發(三)ConcurrentHashMap鎖分段機制

  • Java 5.0 在 java.util.concurrent 包中提供了多種併發容器類來改進同步容器
    的效能。
  • ConcurrentHashMap 同步容器類是Java 5 增加的一個執行緒安全的雜湊表。對
    與多執行緒的操作,介於 HashMap 與 Hashtable 之間。內部採用“鎖分段”
    機制替代 Hashtable 的獨佔鎖。進而提高效能。
  • 此包還提供了設計用於多執行緒上下文中的 Collection 實現:
    ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、
    CopyOnWriteArrayList 和 CopyOnWriteArraySet。當期望許多執行緒訪問一個給
    定 collection 時,ConcurrentHashMap 通常優於同步的 HashMap,
    ConcurrentSkipListMap 通常優於同步的 TreeMap。當期望的讀數和遍歷遠遠
    大於列表的更新數時,CopyOnWriteArrayList 優於同步的 ArrayList。

例子:
在一個方法中對一個List讀的同時又往裡面寫操作,會產生錯誤

class MyThread implements Runnable{
    private  static List<String>list = new ArrayList<String>();

    static{
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }

    @Override
    public void run() {
        Iterator<String> it = list.iterator();
        // 每次讀值的同時又寫值
while(it.hasNext()){ System.out.println(it.next());//讀值 list.add("AA");//寫值 } } }

測試:

public static void main(String[] args) {
        MyThread mt = new MyThread();
        for(int i=0;i<10;i++){
            new Thread(mt).start();
        }

        System.out.println(Thread.currentThread()+"執行完畢"
); }

輸出:

AA
AA
AA
Thread[main,5,main]執行完畢
AA
AA
AA
AA
Exception in thread "Thread-5" Exception in thread "Thread-7" Exception in thread "Thread-6" Exception in thread "Thread-0" AA
AA
AA

我們發現main執行緒的執行雖然列印了語句,但是程式確保錯了
Exception in thread "Thread-5" Exception in thread "Thread-7" Exception in thread "Thread-6" Exception in thread "Thread-0" AA
這是因為在原生的list並未對執行緒安全問題進行優化

CopyOnWriteArrayList/CopyOnWriteArraySet

class MyThread implements Runnable{
    private  static CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>();

    static{
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }

    @Override
    public void run() {
        Iterator<String> it = list.iterator();
        // 每次讀值的同時又寫值
        while(it.hasNext()){
            System.out.println(it.next());//讀值
            list.add("AA");//寫值
        }
    }    
}

主函式不變,測試輸出:
正常執行,沒有報錯

總結:

  • 直接使用傳統的list執行的時候會報錯
  • 使用 CopyOnWriteArrayList、CopyOnWriteArraySet:寫入複製,
  • 每次寫入時底層會複製一個list或set
  • 雖然使得讀寫可以同時進行不報錯但是效率不高