前面文章提到Collections.synchronizedMap()与ConcurrentHashM两者都提供了线程同步的功能。那两者的区别在哪呢?我们们先来看到代码例子。
    下面代码实现一个线程对map进行写操作,另一个线程,读出并打印map数据。

  1. package test.map;
  2. import java.util.Collections;
  3. import java.util.HashMap;
  4. import java.util.Hashtable;
  5. import java.util.Map;
  6. import java.util.Random;
  7. import java.util.concurrent.ConcurrentHashMap;
  8. public class MapTest2 {
  9. private static Map<String, Object> map1 = new HashMap<String, Object>();
  10. private static Map<String, Object> map2 = new Hashtable<String, Object>();
  11. private static Map<String, Object> map3 = new ConcurrentHashMap<String, Object>();
  12. private static Map<String, Object> map4 = Collections.synchronizedMap(new HashMap<String, Object>());
  13. private static Map<String, Object> map = map4;
  14. public static void main(String[] args) {
  15. new Thread(new Runnable() {
  16. @Override
  17. public void run() {
  18. while (true) {
  19. if (map.size() > 0) {
  20. for (Map.Entry<String, Object> entry : map.entrySet()) {
  21. System.out.println(String.format("%s: %s", entry.getKey(), entry.getValue()));
  22. }
  23. map.clear();
  24. }
  25. try {
  26. Thread.sleep((new Random().nextInt(10) + 1) * 1);
  27. } catch (InterruptedException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }
  32. }).start();
  33. new Thread(new Runnable() {
  34. @Override
  35. public void run() {
  36. for (int i = 1; i <= 100; i++) {
  37. map.put("key" + i, "value" + i);
  38. try {
  39. Thread.sleep((new Random().nextInt(10) + 1) * 1);
  40. } catch (InterruptedException e) {
  41. e.printStackTrace();
  42. }
  43. }
  44. }
  45. }).start();
  46. }
  47. }

执行代码,我们发现当类中对象map值取map1,map2,map4时,程序都抛出Java.util.ConcurrentModificationException异常。当map=map3时,代码能正常运行。

Collections.synchronizedMap()与ConcurrentHashMap主要区别是:Collections.synchronizedMap()和Hashtable一样,实现上在调用map所有方法时,都对整个map进行同步,而ConcurrentHashMap的实现却更加精细,它对map中的所有桶加了锁。所以,只要要有一个线程访问map,其他线程就无法进入map,而如果一个线程在访问ConcurrentHashMap某个桶时,其他线程,仍然可以对map执行某些操作。这样,ConcurrentHashMap在性能以及安全性方面,明显比Collections.synchronizedMap()更加有优势。同时,同步操作精确控制到桶,所以,即使在遍历map时,其他线程试图对map进行数据修改,也不会抛出ConcurrentModificationException。
    但是,细心的朋友可能发现了,上面的例子,即使map=map3时,最后打印的结果可以并没有100行。由于,不论Collections.synchronizedMap()还是ConcurrentHashMap对map同步的原子操作都是作用的map的方法上,map在读取与清空之间,线程间是不同步的。上面代码的不足在于,我们对这些同步的map过于信任,而忽略了混合操作带来的影响。正确的方法是,把map的读取和清空看成一个原子操作,给整个代码块加锁。

还有一个区别是:ConcurrentHashMap从类的命名就能看出,它必然是个HashMap。而Collections.synchronizedMap()可以接收任意Map实例,实现Map的同步。看这个例子:

  1. package test.map;
  2. import java.util.Collections;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import java.util.TreeMap;
  6. import java.util.concurrent.ConcurrentHashMap;
  7. public class MapTest4 {
  8. private static void writeMap(Map<String, Object> map) {
  9. for (int i = 0; i < 10; i++) {
  10. map.put("key" + i, "value" + i);
  11. }
  12. }
  13. private static void printMap(Map<String, Object> map) {
  14. for (Map.Entry<String, Object> entry : map.entrySet()) {
  15. System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue());
  16. }
  17. }
  18. public static void main(String[] args) {
  19. Map<String, Object> map1 = new HashMap<String, Object>();
  20. writeMap(map1);
  21. printMap(map1);
  22. System.out.println();
  23. Map<String, Object> map2 = Collections.synchronizedMap(new TreeMap<String, Object>());
  24. writeMap(map2);
  25. printMap(map2);
  26. System.out.println();
  27. Map<String, Object> map3 = new ConcurrentHashMap<String, Object>();
  28. writeMap(map3);
  29. printMap(map3);
  30. }
  31. }

map2由于是个TreeMap,最后打印的结果有按照Key值排序的,而map3显然没法保证结果的有序。

Collections.synchronizedMap()与ConcurrentHashMap的区别的更多相关文章

  1. Collections.synchronizedMap()、ConcurrentHashMap、Hashtable之间的区别

    为什么要比较Hashtable.SynchronizedMap().ConcurrentHashMap之间的关系?因为常用的HashMap是非线程安全的,不能满足在多线程高并发场景下的需求. 那么为什 ...

  2. Collections.synchronizedMap()与ConcurrentHashMap区别

    Collections.synchronizedMap()与ConcurrentHashMap主要区别是:Collections.synchronizedMap()和Hashtable一样,实现上在调 ...

  3. 测试HashTable、Collections.synchronizedMap和ConcurrentHashMap的性能

        对于map的并发操作有HashTable.Collections.synchronizedMap和ConcurrentHashMap三种,到底性能如何呢? 测试代码: package com. ...

  4. Java容器:HashTable, synchronizedMap与ConcurrentHashMap

    首先需要明确的是,不管使用那种Map,都不能保证公共混合调用的线程安全,只能保证单条操作的线程安全,在这一点上各Map不存在优劣. 前文中简单说过HashTable和synchronizedMap,其 ...

  5. HashTable、HashMap、ConcurrentHashMap、Collections.synchronizedMap()区别

    Collections.synchronizedMap()和Hashtable一样,实现上在调用map所有方法时,都对整个map进行同步,而ConcurrentHashMap的实现却更加精细,它对Ha ...

  6. ConcurrentHashMap和 CopyOnWriteArrayList提供线程安全性和可伸缩性 以及 同步的集合类 Hashtable 和 Vector Collections.synchronizedMap 和 Collections.synchronizedList 区别缺点

    ConcurrentHashMap和 CopyOnWriteArrayList提供线程安全性和可伸缩性 DougLea的 util.concurrent 包除了包含许多其他有用的并发构造块之外,还包含 ...

  7. ConcurrentHashMap vs Collections.synchronizedMap()不同

    之前项目中,有用到过Collections.synchronizedMap(),后面发现当并发数很多的时候,出现其他请求等待情况,因为synchronizedMap会锁住所有的资源,后面通过查阅资料, ...

  8. SynchronizedMap和ConcurrentHashMap 区别

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt215 SynchronizedMap和ConcurrentHashMap的深 ...

  9. HashMap、Hashtable、LinkedHashMap、TreeMap、ConcurrentHashMap的区别

    Map是Java最常用的集合类之一.它有很多实现类,我总结了几种常用的Map实现类,如下图所示.本篇文章重点总结几个Map实现类的特点和区别: 特点总结: 实现类 HashMap LinkedHash ...

随机推荐

  1. Monte Carlo计算Pi,python实现

    Monte Carlo import random import matplotlib.pyplot as plt import numpy as np 6 # 函数模拟点的随机掉落,并分为两组 de ...

  2. Revit API创建标注NewTag

    start ;             )                 {                     eId = item;                 }            ...

  3. linux 启动 Oracle 实例

    启动数据库实例,分为两步:第一步,启动监听:第二步,启动数据库实例. 一.如何启动数据库实例 1.进入到sqlplus启动实例 --“切换到oracle用户” su - oracle --“打开监听” ...

  4. 如何使用Bootstrap自带图标

    查看可用的字体图标列表: http://www.runoob.com/try/demo_source/bootstrap3-glyph-icons.htm 第一步:下载Bootstrap,发现目录中包 ...

  5. JVM Debugger Memory View for IntelliJ IDEA

    Posted on August 19, 2016 by Andrey Cheptsov Every day we try to find new ways to improve developer ...

  6. Python报错:ImportError: No module named src.data_layer

    ImportError: No module named src.data_layer 解决方案: export PYTHONPATH=path/to/modules

  7. (转)GPU图形绘制管线

    摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU编程与CG语言之阳春白雪下里巴人”第二章. 图形绘制管线描述GPU渲染流程, ...

  8. 如何用 async 控制流程

    来自: http://larry850806.github.io/2016/05/31/async/ [Javascript] 如何用 async 控制流程 (一) 31 May 2016 async ...

  9. C# 6 的新特性~

    原文地址 Mads Torgersen,微软 C# 程序管理者,它发布了一个视频,描述即将到来的下一个 C# 版本--C# 6.在 C# 6 的新特性之间,Mads 主要提到了 getter-only ...

  10. EditText控件设置只读

    android的文本框输入控件(EditText),有时需要设置控件为只读,最简单的方法就是在layout xml文件中设置EditText的android:editable属性值为false即可,但 ...