Java中SynchronizedMap与ConcurrentHashMap的对比

如何使用

概述

  • ConcurrentHashMap:

    线程安全;
    其将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都有锁存在,那么在插入元素的时候就要先找到应该插入到哪一个片段segment,然后再在这个片段上面进行插入,而且这里还需要获取segment锁(即锁分段技术);
    ConcurrentHashMap让锁的粒度更精细一些,并发性能更好

  • SynchronizedMap:

    线程安全;
    通过synchronized关键字进行同步控制;
    所有单个的操作都是线程安全的,但是多个操作组成的操作序列却可能导致数据争用,因为在操作序列中控制流取决于前面操作的结果。这也被称作是:有条件的线程安全性
    效率低

两者源码对比

  哈希表声明:通过下面两图对比可以发现,两者的区别在于volatile关键字


  • ConcurrentHashMap:

  • SynchronizedMap:

  put()方法:


  • ConcurrentHashMap:

  • SynchronizedMap:

  get()方法:


  • ConcurrentHashMap:

  • SynchronizedMap:

ConcurrentHashMap详解

  1. 与HashTable容器对比:HashTable容器在竞争激烈的并发环境下表现出效率底下的原因是所有访问HashTable的线程都必须竞争同一把锁(其实现是在对应的方法上添加了synchronized关键字进行修饰),那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
  2. get()方法:其高效之处在于整个get过程不需要加锁,除非读到的值是空的才会加锁重读。get方法里将要使用的共享变量都定义成volatile,如用于统计当前Segement大小的count字段和用于存储值的HashEntry的value。定义成volatile的变量,能够在线程之间保持可见性,能够被多线程同时读,并且保证不会读到过期的值,但是只能被单线程写(有一种情况可以被线程写,就是写入的值不依赖于原值),在get操作里只需要读不需要写共享变量count和value,所以可以不用加锁。
  3. put()方法:首先定位到Segment,然后在Segment里进行插入操作。插入操作需要经历两个步骤,第一步判断是否需要对Segment里的HashEntry数组进行扩容,第二步定位添加元素的位置然后放在HashEntry数组里。
  4. 具体实现:在ConcurrentHashMap的实现中使用了一个包含16个锁的数组,每个锁保护所有散列桶的1/16,其中第N个散列桶由第(N mod 16)个锁来保护。假设散列函数具有合理的分布性,并且关键字能够实现均匀分布,那么这大约能把对于锁的请求减少到原来的1/16。正是这项技术使得其能够支持多达16个并发的写入器。
  5. 缺点:当ConcurrentHashMap需要扩展映射范围,以及重新计算键值得散列值要分布到更大的桶集合中时,就需要获取分段锁集合中所有的锁(要获取内置锁的一个集合,采用的唯一方式是递归)。
时间: 2024-08-05 21:22:22

Java中SynchronizedMap与ConcurrentHashMap的对比的相关文章

Java中BufferedReader和scanner的对比

Scanner 和BufferedReader同样能实现将键盘输入的数据送入程序, import java.io.*;import java.util.Scanner;public class C {public static void main(String []args) throws IOException{ String x1,x2;    int sum=0; System.out.print("BufferedReader方法\ninput two number:"); /

Java中ConcurrentHashMap的实现

Java中ConcurrentHashMap的实现 ConcurrentHashMap(简写CHM)引入了分割,并提供了HashTable支持的所有的功能.在CHM中,支持多线程对Map做读操作,并且不需要任何的blocking.这得益于CHM将Map分割成了不同的部分,在执行更新操作时只锁住一部分.根据默认的并发级别(concurrency level),Map被分割成16个部分,并且由不同的锁控制.这意味着,同时最多可以有16个写线程操作Map.试想一下,由只能一个线程进入变成同时可由16个

JAVA中TCP和UDP传输例子的对比

在本文中我将学到的java中的UDP和TCP在局域网内的传输做了对比,这里强调 的是局域网范围内,非广域网.首先,下面的是我写的在局域网内利用java中的UDP协议写的一个传输文件或者图片的类. --------------------------------------------------------------------------------------------------------------------------------------------------------

Java中的NIO和IO的对比分析

总的来说,java中的IO和NIO主要有三点区别: IO                  NIO 面向流     面向缓冲 阻塞IO  非阻塞IO  无   选择器(Selectors) 1.面向流与面向缓冲 Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的. Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方.此外,它不能前后移动流中的数据.如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区. Java

Java中json工具对比分析

Java中几个json工具分析 1, 环境 JDK1.6+IDE(IntelliJ IDEA)+windowsXP+GBK编码 2,分析对象 jackson1.8.2 http://jackson.codehaus.org/ gson1.7.1 http://code.google.com/p/google-gson/ jsob_lib2.4 http://json-lib.sourceforge.NET/ 3,使用实例          用两个bean进行测试,两个bean都嵌套有数组和对象,

c++中继承和java中继承的对比

java中: class Parent{ public void test(int a){ System.out.println("Parent:" + a); System.out.println(this.getClass().getName()); } } class Child extends Parent{ public void test(int a, int b){ System.out.println("Child:" + a + " &q

Java中基本数据类型的对比记忆

Java中八种基本类型数据情况: 数据类型 所占字节数 所占位数(二进制位数) 可表示范围 默认值 包装类 备注 byte(字节) 1 8 -128 - 127  0  Byte   short(短整型) 2 16 -32768 - 32768   0  Short    int(整型) 4 32 -2147483648-2147483648   0 Integer    long(长整型) 8 64 -9233372036854477808-9233372036854477808  0  Lo

Java中读取Map的两种方法对比

引言: 在Java中Map的使用非常频繁,我们经常会需要对Map进行遍历和读取,下面将展示两种遍历的方法以及简要分析. 1.  遍历Map方法A Map map = new HashMap(); Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); Object key = entry.getKey(); Object val =

java中运算符instanceOf和Class<?>.isInstance的对比

辨析一个类和一个实例是不是具有实现关系,通常使用 instanceOF和Class<?>.isInstanceOf(obj),为了能够更好的使用这2中方式,我们需要知道两者的差别. //通常我们会用到下面的关系,instanceOf说明了类和对象的直接实现关系 if(obj instanceOf ObjClass) { //..   } //这种关系是如何实现的呢 //首先obj 是ObjClass的实例的话,那么obj必须是非空,所以 obj!=null,其次,obj.getClass()=