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。

HashMap与Hashtable 的底层是一样的,Hashtable是线程安全的,hashtable会给整个Hash表加上锁,导致运行效率非常低。使用Hashtable进行操作时,并没有达到并行的目的,相当于并行转串行。

Hashtable还存在复合操作: 复合操作也是线程不安全的

  "若不存在则添加"

  "若存在则删除"

  if(table.contains()){

    //table.put()

  }

ConcurrentHashMap 采用 "锁分段" 机制

  ConcurrentHashMap 中有一个级别 叫 ConcurrentLevel,默认级别为16

  即分为16个段,默认有16个段(Segment),每个段中有一个独立hash表,默认Hash表长度为16

  每个段都是一个独立的锁,这就意味着线程多个线程访问不同的段是互不干扰的,达到并行的目的

  

CopyOnWriteArrayList

package com.java.juc;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


public class TestCopyOnWriteArrayList {

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

}

class HelloThread implements Runnable{
    private static List<String> list = new ArrayList<>();
    
    static{
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }
    
    public void run() {
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        
        list.add("DD");
    }
}

会出现如下问题:

Exception in thread "Thread-9" Exception in thread "Thread-7" Exception in thread "Thread-5" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at com.java.juc.HelloThread.run(TestCopyOnWriteArrayList.java:33)
    at java.lang.Thread.run(Unknown Source)
java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at com.java.juc.HelloThread.run(TestCopyOnWriteArrayList.java:33)
    at java.lang.Thread.run(Unknown Source)
java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at com.java.juc.HelloThread.run(TestCopyOnWriteArrayList.java:33)
    at java.lang.Thread.run(Unknown Source)
Exception in thread "Thread-4" Exception in thread "Thread-0" Exception in thread "Thread-1" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at com.java.juc.HelloThread.run(TestCopyOnWriteArrayList.java:33)
    at java.lang.Thread.run(Unknown Source)

可以使用 CopyOnWriteArrayList 解决问题:

package com.java.juc;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;


public class TestCopyOnWriteArrayList {

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

}

class HelloThread implements Runnable{
//    private static List<String> list = new ArrayList<>();
    private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
    
    static{
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }
    
    public void run() {
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        
        list.add("DD");
    }
}

注意:添加操作多时,效率低,因为每次添加时都会进行复制,开销非常大。并发迭代操作多时可以选择。

原文地址:https://www.cnblogs.com/wq3435/p/6341731.html