Java-JUC(四):同步容器介绍

本文介绍了Java中同步容器的概念及重要性,对比了HashMap与HashTable的线程安全性问题,并详细解析了ConcurrentHashMap的工作原理及其在不同JDK版本中的实现差异。此外,通过实例展示了CopyOnWriteArrayList的应用场景与优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

同步容器简介

针对容器我们知道有HashMap,HashTable,其中HashMap是一个非线程安全的,HashMap在并发执行put操作时会引起死循环,导致CPU利用率接近100%。因为多线程会导致HashMap的Node链表形成环形数据结构,一旦形成环形数据结构,Node的next节点永远不为空,就会在获取Node时产生死循环,而且死循环发生在发生在扩容时

HashTable是线程安全的,但是在复合操作上会线程不安全的现象。

备注:

1)什么是复合操作?比如添加元素,需先判断是否元素存在,元素不存在时才添加。

2)hashtable是在插入和删除上都是索表的方式,因此效率特别低。

在jdk1.5之后提供java.util.concurrent包下的一些同步容器:java.util.concurrent.ConcurrentHashMap<K, V>。

ConcurrentHashMap性能讲解:

ConcurrentHashMap的性能要比HashTable性能高,而且高很多。

1)ConcurrentHashMap在jdk1.7之前采用了“锁分段”机制,默认把一个ConcurrentHashMap分为16个segment,每个segment下默认也是长度为16的哈希表,在每个哈希元素下是链表。这样就可默认每段有一个锁,一次可以最大并发操作16。

2)在jdk1.8之后ConcurrentHashMap采用CAS算法,可以把CAS算法错略的认为是无锁算法。

3)java.util.concurrent包还提供了设计用于多线程上下文中的Collection实现:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList和CopyOnWriteArraySet。

4)当希望许多线程访问一个给定的Collection时

  a)ConcurrentHashMap由于同步的HashMap;

  b)ConcurrentSkipListMap通常优于同步的TreeMap;

5)当期望的读数和遍历远远大于列表的更新数时,CopyOnWriteArrayList优于同步的ArrayList。

CopyOnWriteArrayList的用法示例:

测试ArrayList并发读写:

package com.dx.juc.test;

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

public class CopyOnWriteTest {
    public static void main(String[] args) {
        new Thread(new MyCopyOnWrite()).start();
    }
}

class MyCopyOnWrite implements Runnable {
    private static List<String> items = Collections.synchronizedList(new ArrayList<String>());

    static {
        items.add("A");
        items.add("B");
        items.add("C");
    }

    public void run() {
        for (String item : items) {
            System.out.println(item);
            items.add("D");
        }
    }

}

在执行时,抛出异常:

A
Exception in thread "Thread-0" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at com.dx.juc.test.MyCopyOnWrite.run(CopyOnWriteTest.java:23)
    at java.lang.Thread.run(Thread.java:745)

如果使用CopyOnWriteArrayList时,并不会抛出异常,原理是每次在写入时,会在底层拷贝一份新的数据,因此如果是写入时性能不高。

package com.dx.juc.test;

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

public class CopyOnWriteTest {
    public static void main(String[] args) {
        MyCopyOnWrite myCopyOnWrite = new MyCopyOnWrite();

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

class MyCopyOnWrite implements Runnable {
    private static CopyOnWriteArrayList<String> items = new CopyOnWriteArrayList<String>();

    static {
        items.add("A");
        items.add("B");
        items.add("C");
    }

    public void run() {
        System.out.println(Thread.currentThread().getName() + ":start");
        Iterator<String> iterator = items.iterator();
        while (iterator.hasNext()) {
            System.out.println(Thread.currentThread().getName() + ":" + iterator.next());
            items.add("D");
        }
        System.out.println(Thread.currentThread().getName() + ":end");
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值