JUC-3.ConcurrentHashMap锁分段机制

一、同步容器与并发容器

1. 同步容器

早起的JDK中,有两种现成的同步容器,Vector和HashTable,可以直接new对象获取 ;
在JDK1.2中,引入了同步封装类,可以由Collections.synchronizedXxxx等方法创建;

同步容器的问题
  1. HashTable 效率低
  2. 符合操作存在安全问题,需要额外加锁保护;
常见复合操作如下:

迭代:反复访问元素,直到遍历完全部元素;
跳转:根据指定顺序寻找当前元素的下一个(下n个)元素;
条件运算:例如若没有则添加等
例子:

if (!table.contants()) {
    table.put();
}
迭代器及快速失败问题

同步容器与非同步容器一样,在迭代期间,若其它线程并发修改该容器,会抛出ConcurrentModificationException异常,即快速失败机制。

实现原理

通过计数器记录容器修改次数,在迭代时,如hasNext等方法调用时遇到计数器数值变化则抛出异常。

解决

通过在容器迭代期间对容器加锁来解决该问题是一种方式,但并发性差,当容器规模大时,更加严重,而且还可能产生死锁问题;一种更优的解决方式,如上面链接里提到的,采用克隆容器(CopyOnWriteArrayList等),在副本上进行操作,但存在显著的性能开销,需要拷贝数组等操作,这种方式的好坏要看具体需求,如容器大小,执行的具体操作,调用频率等,一般当迭代操作远多于修改操作时,比较适用克隆容器;

隐藏的迭代操作

另外,在集合中,有一些隐藏的迭代操作,如toString,equals,hashCode等方法,使用时需注意,也可能会抛出ConcurrentModificationException异常;

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

/** * CopyOnWriteArrayList/CopyOnWriteArraySet:写入并复制。 * @author xiaobin * @date 2018/3/5 */
public class TestCopyOnWriteArrayList {

    public static void main(String[] args) {
        HelloTread ht = new HelloTread();

        for (int i = 0  ; i < 10; i++) {
            new Thread(ht).start();
        }
    }

}


class HelloTread implements Runnable {

    private static List<String> list = Collections.synchronizedList(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());

            //迭代期间容器发生变化,fail-fast
            list.add("AA");
        }

    }
}

2. 并发容器

在Java 5.0 后,java.util.concurent包中提供了多种并发容器类来改进同步容器的性能。
如:
ConcurrentHashMap是一个线程安全的哈希表。在多线程访问时优于HashMap
ConcurrentSkipListMap 优于TreeMap
ConcurrentSkipListSet
CopyOnWriteArrayList 当期望的读数和遍历远远大于列表更新数时优于ArrayList。如:大量监听器时使用
CopyOnWriteArraySet

CopyOnWriteArrayList

写入并复制;每次添加时,都会复制一个容器的副本,再添加。当多个线程并发操作多时使用此容器。

上面例子修改容器为CopyOnWriteArrayList避免了fail-fast。

private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
ConcurrentHashMap

并发容器包下的ConcurrentHashMap也是采用CAS操作,同时应用锁分段机制,提供了访问效率。

原子操作

增加了若干原子操作方法,如putIfAbsent(没有该key,则添加);

如果不存在(新的entry),那么会向map中添加该键值对,并返回null。
如果已经存在,那么不会覆盖已有的值,直接返回已经存在的值。

迭代器弱一致性

迭代期间不会抛出ConcurrentModificationException异常;

size()、isEmpty()等方法返回的是一个近似值;

锁分段结构

《JUC-3.ConcurrentHashMap锁分段机制》

    原文作者:JUC
    原文地址: https://blog.csdn.net/xbliu564/article/details/79452638
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞