Java——你需要了解一下HashMap、Hashtable、ConcurrentHashMap的区别

简介: Java——你需要了解一下HashMap、Hashtable、ConcurrentHashMap的区别

写在前面


听别人说,在面试过程中,面试官经常会问到一个问题: HashMap、Hashtable、ConcurrentHashMap这三者有什么区别?


简单的来说:


  • HashMap是线程不安全的,当出现多线程操作时,会出现安全隐患。
  • HashTable是线程安全的,其中所有的方法都加上了synchronized关键字,也就是说HashTable用的是方法锁,把整个put方法都上锁了,这就导致了效率很低。如果把put方法比作是一个有很多房间的院子,那么HathTable的锁就相当于是把院子的大门锁上了,导致你进不去这个院子。
  • ConcurrentHashMap也是线程安全的,但是它是用的块锁(synchronized关键字修饰的不再是整个方法体,而是部分代码块)。这里仍然把put方法比作一个有很多房间的院子,那么它相当于是把院子里的有安全隐患的房间锁上了,这样一来,其他房间仍然可以进入,只是存在安全隐患的房间你暂时进不去了。

下面,我用三个简单的代码实例来解释一下吧。


HashMap


HashMap是线程不安全的,在源码中对put方法没有做锁的处理,当面对多线程时,会有线程安全问题。


下面通过一个简单的例子进行演示,创建三个线程,并且启动,在run方法里通过for循环给map存100个值,然后输出map的大小按正常来说,该map的大小应该是100,而这里输出了190。


import java.util.HashMap;
import java.util.Map;
/**
 *
 */
public class HashMapTest implements Runnable {
    static Map<String,String> map=new HashMap<>();
    @Override
    public void run() {
        long startTime=System.currentTimeMillis();
        for (int i=0;i<100;i++) {
            map.put(i + "","value");
        }
        long endTime=System.currentTimeMillis();
        System.out.println((endTime-startTime) + "ms");
    }
    public static void main(String[] args) {
        Thread thread1=new Thread(new HashMapTest());
        Thread thread2=new Thread(new HashMapTest());
        Thread thread3=new Thread(new HashMapTest());
        thread1.start();
        thread2.start();
        thread3.start();
        Thread currentThread=Thread.currentThread();
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(map.size());
    }
}



Hashtable


HashTable用到了锁,而且是直接给put方法加的锁,线程肯定是安全的了,这里我们在测试线程安全的同时,看一下执行时间。



import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
/**
 *
 */
public class HashtableTest implements Runnable {
    static Map<String,String> map=new Hashtable<>();
    @Override
    public void run() {
        long startTime=System.currentTimeMillis();
        for (int i=0;i<100;i++) {
            map.put(i + "","value");
        }
        long endTime=System.currentTimeMillis();
        System.out.println((endTime-startTime) + "ms");
    }
    public static void main(String[] args) {
        Thread thread1=new Thread(new HashtableTest());
        Thread thread2=new Thread(new HashtableTest());
        Thread thread3=new Thread(new HashtableTest());
        thread1.start();
        thread2.start();
        thread3.start();
        Thread currentThread=Thread.currentThread();
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(map.size());
    }
}



这里可以看到,多次反复执行这段代码,最终获取到map集合的size始终是100,不多不少刚刚好,存储的时间大概在12ms左右。


ConcurrentHashMap


ConcurrentHashMap用的是块锁,哪块不安全就锁哪块,不能不锁,不能全锁,那我就块锁!看看这个块锁相对于Hashtable的方法锁是快了,还是慢了。



import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 *
 */
public class ConcurrentHashMapTest implements Runnable {
    static Map<String,String> map=new ConcurrentHashMap<>();
    @Override
    public void run() {
        long startTime=System.currentTimeMillis();
        for (int i=0;i<100;i++) {
            map.put(i + "","value");
        }
        long endTime=System.currentTimeMillis();
        System.out.println((endTime-startTime) + "ms");
    }
    public static void main(String[] args) {
        Thread thread1=new Thread(new ConcurrentHashMapTest());
        Thread thread2=new Thread(new ConcurrentHashMapTest());
        Thread thread3=new Thread(new ConcurrentHashMapTest());
        thread1.start();
        thread2.start();
        thread3.start();
        Thread currentThread=Thread.currentThread();
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(map.size());
    }
}



可以看到,这里最终获取到的map集合的size始终是100,而且存储时间较Hashtable也有一定的缩短,基本在10ms左右。


相关文章
|
6天前
|
存储 安全 Java
一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)
这篇文章是关于Java面试的第二天笔记,涵盖了HashMap与HashTable的区别、ConcurrentHashMap的实现原理、IOC容器的实现方法、字节码的概念和作用、Java类加载器的类型、双亲委派模型、Java异常体系、GC如何判断对象可回收、线程的生命周期及状态,以及sleep、wait、join、yield的区别等十道面试题。
一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)
|
6天前
|
存储 关系型数据库 MySQL
一天五道Java面试题----第八天(怎么处理慢查询--------->简述Myisam和innodb的区别)
这篇文章是关于Java面试中关于数据库性能优化和MySQL特性的五个问题,包括处理慢查询、ACID特性保证、MVCC概念、MySQL主从同步原理以及MyISAM和InnoDB存储引擎的区别。
|
6天前
|
前端开发 Java 编译器
【前端学java】java中的Object类和前端中的Object有什么区别(9)
【8月更文挑战第10天】java中的Object类和前端中的Object有什么区别
14 0
【前端学java】java中的Object类和前端中的Object有什么区别(9)
|
1天前
|
Java
"Java排序大揭秘:Comparable与Comparator,究竟有何神秘区别?掌握它们,告别排序难题!"
【8月更文挑战第19天】Java提供Comparable与Comparator两种排序机制。Comparable位于`java.lang`包,定义了`compareTo()`方法以实现类的自然排序;Comparator位于`java.util`包,通过`compare()`方法提供外部定制排序。实现Comparable固定了排序策略,适用于类自带排序逻辑;使用Comparator则可在不改动类的前提下灵活定义多种排序规则,适合多样化的排序需求。选择合适机制可优化排序效率并增强代码灵活性。
|
安全 算法 Java
java HashTable源码解析
本文基于JDK1.7,HashTable是用同步来实现线程安全的Map,使用Hash算法定位 与HashMap类似,HashMap是线程不安全的,单线程下效率更高,多线程下ConcurrentHashMap可保证线程安全且效...
773 0
|
存储 Java 索引
Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例
概要 前一章,我们学习了HashMap。这一章,我们对Hashtable进行学习。我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable。第1部分 Hashtable介绍第2部分 Hashtable数据结构第3部分 Hashtable源码解析(基于JDK1.
821 0
|
6天前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。