JUC系列之(四)ConcurrentHashMap锁分段机制

ConcurrentHashMap锁分段机制

1. 关于HashMap和HashTable

HashMap:线程不安全

HashTable:

  1. 效率低:操作时锁整个表

  2. 复合操作会带来安全问题

    // table.contains()和table.put()分别都是加了锁的,但是像下述复合操作,一个线程判断完之后CPU可能被其他线程抢夺,带来安全问题
    if(!table.contains(element)){
      table.put(element)
    }
    

2. 锁分段机制

ConcurrentHashMap锁分段机制是在JDK 1.7的时候用的,JDK1.8有了很大的改变

类型 JDK1.7 JDK1.8
数据结构 Segment分段锁 数组+链表+红黑树
线程安全机制 Segment的分段锁机制 CAS+Synchorized机制
锁的粒度 每段Segment加锁,粒度大 每个Node元素加锁,粒度更细
遍历时间复杂度 O(n) O(logN)

介绍下JDK 1.7的锁分段机制

3. 多线程Collection

HashMap   =》  ConcurrentHashMap
TreeMap   =》  ConcurrentSkipListMap
ArrayList =》  CopyOnWriteArrayList

Collections.synchronizedXXX()的工作原理:为XXX的每个操作都包上一层synchronized

Collections.synchronizedXXX()存在的问题

package com.atguigu.juc;

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

public class TestCopyAndWriteArrayList {
    public static void main(String[] args) {
        HelloThread helloThread = new HelloThread();

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

class HelloThread 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> iterator = list.iterator();

        while (iterator.hasNext()){
            // 边读边写
            System.out.println(iterator.next());

            list.add("AA");
        }
    }
}

出现上述问题的原因是迭代读取的数据源和写入的数据源是同一个

使用CopyOnWriteArrayList 可解决上述问题

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

替换为

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

即可

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

posted @ 2024-02-29 19:30  刘二水  阅读(164)  评论(0)    收藏  举报