java并发编程-ConcurrentHashMap的基本原理和使用

概述

本文介绍ConcurrentHashMap的原理,并通过例子讲解如何在多线程环境下使用ConcurrentHashMap。

ConcurrentHashMap要点

  • 与Hastable或synchronizedMap会锁住整个map来保证线程安全,而ConcurrentHashMap允许读线程和写线程的并发地进行操作。 也就是说,ConcurrentHashMap允许同时有一些线程修改map,其他一些线程读取map中的数据。而Hastable或synchronizedMap只允许在一个时间点只有一个线程进行操作。
  • ConcurrentHashMap允许任意数量的并发读线程和有限数量的并发写入线程,并且读取和写入线程可以同时在map上进行操作。
    • 读取线程(reader)执行检索操作,例如get,containsKey,size,isEmpty,并迭代映射的键集。
    • 写线程(writer)执行更新操作,例如put和remove。
  • ConcurrentHashMap的迭代器是弱一致的,这意味着迭代器可能不会反映自构造以来的最新更新。迭代器应该只由一个线程使用,如果在使用迭代器时修改了映射,则不会抛出ConcurrentModificationException。
  • 不像阻塞容器对整个容器加锁,ConcurrentHashMap使用了比较细粒度的锁来实现,这样可以保证读者和写者同时进行操作。

ConcurrentHashMap例子

package ConcurrentCollections;

import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ConcurrentHashMapExp {
    private final ConcurrentHashMap<Integer,String> conHashMap = new ConcurrentHashMap<Integer,String>();

    public static void main(String[] args) {
        ExecutorService  service = Executors.newFixedThreadPool(4);
        ConcurrentHashMapExp ob = new ConcurrentHashMapExp();

        service.execute(ob.new WriteThreasOne());
        service.execute(ob.new WriteThreasTwo());
        service.execute(ob.new ReadThread("read1"));
        service.execute(ob.new ReadThread("read2"));
        service.shutdown();
    }

    // producer1
    class WriteThreasOne implements Runnable {

        @Override
        public void run() {
                for (int i = 0; ; i++) {
                    // 若i不存在,则放入到并发map
                    conHashMap.putIfAbsent(i, "A" + i);
                    System.out.println(Thread.currentThread().getName() + "put: " + "A"+i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        }
    }

    // producer2
    class WriteThreasTwo implements Runnable {
        @Override
        public void run() {
            for(int i= 1000; i<=2000; i++) {
                conHashMap.put(i, "B"+ i);
                System.out.println(Thread.currentThread().getName() + "put: " + "B"+i);

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // consumer1
    // 通过迭代器遍历并发map的元素
    // 注意:每次迭代器都是从头开始迭代。
    class ReadThread implements Runnable {
        private final String name;

        public ReadThread(String name) {
           this.name = name;
           System.out.println("Start: " + this.name);
        }

        @Override
        public void run() {
            // 注意:若把迭代器构建写在这里,在循环内部将不会获取到新添加的key-valu值。
            // Iterator<Integer> ite = conHashMap.keySet().iterator();

            for (int j = 1; ; j++) {
                Iterator<Integer> ite = conHashMap.keySet().iterator();
                while (ite.hasNext()) {
                    Integer key = ite.next();
                    System.out.println(this.name + " get " + key + " : " + conHashMap.remove(key));
                }

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

ConcurrentHashMap 与 Hashtable

  • ConcurrentHashMap基于hash表实现,允许放入空元素,但Hashtable不允许。
  • get(),put(),remove()等方法在Hashtable中会进行同步,而ConcurrentHashMap不使用synchronized方法进行并发同步。
  • 在并发修改时,迭代访问Hashtable元素将抛出ConcurrentModificationException,而ConcurrentHashMap则不会。

ConcurrentHashMap 和 HashMap

  • ConcurrentHashMap是线程安全的,而HashMap不是(若是多个线程同时写入需要进行同步)。
  • ConcurrentHashMap和HashMap都是基于hash表实现。
  • ConcurrentHashMap支持检索的完全并发。而HashMap需要使用Collections.synchronizedMap()进行同步。
  • ConcurrentHashMap为实例化时可以更改的更新提供并发级别。
  • 在并发修改中,HashMap抛出ConcurrentModificationException,而ConcurrentHashMap则不会。

ConcurrentHashMap 和 HashMap 和 Hashtable

  • HashMap不是线程安全的Map,不应该被多个线程同时使用。
  • Hashtable是线程安全的Map,在同一时间只允许一个线程执行read/update操作。
  • SynchronizedMap基于Map实现了线程安全的封装。它由Collections.synchronizedMap(Map)工厂方法生成。synchronizedMap也只允许一次只有一个线程在map上操作。
  • ConcurrentHashMap是一个线程安全的Map,具有更大的灵活性和更高的可伸缩性,因为它使用一种特殊的锁定机制,使多个线程能够同时读取/更新map。

总结

本文介绍了ConcurrentHashMap的基本原理,并通过一个实际的例子来说明它的用法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值