HashMap、Hashtable、ConcurrentHashMap线程安全性分析

先看代码:

HashMap

package com.hash;

import java.util.HashMap;
import java.util.Map;

public class HashMapTest {
    /**
     * NUMBER = 50,表示 50 个线程分别执行 put 方法 50 次 线程安全的情况下因该 map size 应该为 2500
     */
    public static final int NUMBER = 50;

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        for (int i = 0; i < NUMBER; i++) {
            new Thread(new HashMapTask(map)).start();
        }

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("map size = " + map.size());
    }
}

class HashMapTask implements Runnable {

    Map<String, String> map;

    public HashMapTask(Map<String, String> map) {
        this.map = map;
    }

    @Override
    public void run() {
        for (int i = 0; i < HashMapTest.NUMBER; i++) {
            map.put(i + "-" + Thread.currentThread().getName(), "test");
        }
    }
}

运行结果:

开了 50 个线程往 HashMap 中添加元素,每个线程执行 50 次 put 方法,在线程安全的情况下,map 中应该有 2500 个键值对,但是执行的结果大都是小与 2500 的(并不会产生死循环)。

Hashtable

package com.hash;

import java.util.Hashtable;

public class HashTableTest {
    /**
     * NUMBER = 50,表示 50 个线程分别执行 put 方法 50 次
     * 线程安全的情况下因该 table size 应该为 2500
     */
    public static final int NUMBER = 50;
    public static void main(String[] args) {
        Hashtable<String, String> table = new Hashtable<>();
        for (int i = 0; i < NUMBER; i++) {
            new Thread(new HashTableTask(table)).start();
        }

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

        System.out.println("table size = " + table.size());
    }
}

class HashTableTask implements Runnable {

    Hashtable<String, String> table;

    public HashTableTask(Hashtable<String, String> table) {
        this.table = table;
    }

    @Override
    public void run() {
        for (int i = 0; i < HashTableTest.NUMBER; i++) {
            table.put(i + "-" + Thread.currentThread().getName(), "test");
        }
    }
}

运行结果:

无论运行多少次,结果都是size=2500。

ConcurrentHashMap

package com.hash;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapTest {
    /**
     * NUMBER = 50,表示 50 个线程分别执行 put 方法 50 次 线程安全的情况下因该 map size 应该为 2500
     */
    public static final int NUMBER = 50;

    public static void main(String[] args) {
        Map<String, String> map = new ConcurrentHashMap<>();
        for (int i = 0; i < NUMBER; i++) {
            new Thread(new ConcurrentHashMapTask(map)).start();
        }

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("map size = " + map.size());
    }
}

class ConcurrentHashMapTask implements Runnable {

    Map<String, String> map;

    public ConcurrentHashMapTask(Map<String, String> map) {
        this.map = map;
    }

    @Override
    public void run() {
        for (int i = 0; i < ConcurrentHashMapTest.NUMBER; i++) {
            map.put(i + "-" + Thread.currentThread().getName(), "test");
        }
    }
}

运行结果:

无论运行多少次,结果都是size=2500。

总结:

1.HashMap是线程不安全的。

2.Hashtable和ConcurrentHashMap是线程安全的。

我想线程安全但是我又想效率高?

使用 ConcurrentHashMap,其底层采用分段的数组+链表实现,线程安全,通过把 Map 分为 N 个 Segment(部分),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。

Hashtable 之所以效率低主要是使用了 synchronized 关键字对 put 等操作进行加锁,而 synchronized 关键字加锁是对整张 Hash 表的,即每次锁住整张表让线程独占,致使效率低下,而 ConcurrentHashMap 在对象中保存了一个 Segment 数组,即将整个Hash表划分为多个分段;而每个Segment元素,即每个分段则类似于一个Hashtable;这样,在执行put操作时首先根据hash算法定位到元素属于哪个Segment,然后对该Segment加锁即可,因此, ConcurrentHashMap 在多线程并发编程中可是实现多线程put操作。

原文地址:https://www.cnblogs.com/gaopengpy/p/11916932.html

时间: 2024-08-04 13:41:19

HashMap、Hashtable、ConcurrentHashMap线程安全性分析的相关文章

[Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.

注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhangerqing/article/details/8193118 Java集合类是个非常重要的知识点,HashMap.HashTable.ConcurrentHashMap等算是集合类中的重点,可谓"重中之重",首先来看个问题,如面试官问你:HashMap和HashTable有什么区别,一个比较简

HashMap Hashtable ConcurrentHashMap 一点区别

HashMap  ConcurrentHashMap Hashtable 工作中经常会用到, HashMap用的最多, ConcurrentHashMap次之,hashTable用的最少. 简单看了下源码,其实原因还是挺明显的.从JDK的发展历程来看,hashTable是1.0就发布的,属于最早的key-value形式的存储, 到了1.2才有hashMap, ConcurrentHashMap是1.5中发布的,它们的实现有很多类同,也有很多细节上的区别.这里主要通过查看源码来比较下它们在写入与读

HashMap HashTable ConcurrentHashMap 简单比较

1. HashMap HashTable ConcurrentHashMap都是java哈希算法的实现,其中HashMap是非线程安全的,HashTable 和ConcurrentHashMap是线程安全的.单线程环境下HashMap更有速度优势. 2. HashTable 的实现方式比较简单粗暴,直接对修改操作进行加锁来控制并发访问. 3. ConcurrentHashMap,通过分段(segment)来提高并发性能,进行修改操作时,只是对相应的段进行加锁,理论上段个数的线程可以并行访问Con

Spring 中获取 request 的几种方法,及其线程安全性分析

概述在使用Spring MVC开发Web系统时,经常需要在处理请求时使用request对象,比如获取客户端ip地址.请求的url.header中的属性(如cookie.授权信息).body中的数据等.由于在Spring MVC中,处理请求的Controller.Service等对象都是单例的,因此获取request对象时最需要注意的问题,便是request对象是否是线程安全的:当有大量并发请求时,能否保证不同请求/线程中使用不同的request对象.这里还有一个问题需要注意:前面所说的"在处理请

JDK1.8中的HashMap.HashTable, ConcurrentHashMap有什么区别?

JDK1.8中的HashMap,HashTable,ConcurrentHashMap有什么区别? 答:HashMap是线程不安全的,底层采用数组+链表+红黑树的结构 HashTable是线程安全的,因为使用了Synchronized锁住了整个table,底层采用了数组+链表 ConcurrentHashMap是线程安全的,采用了CAS+同步锁Synchronized对链表头节点进行锁定,底层使用数组+链表+红黑树 HashMap的key和value可以是null,其他两个不行. 原文地址:ht

Spring中如何获取request的方法汇总及其线程安全性分析

前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性.下面话不多说了,来一起看看详细的介绍吧. 概述 在使用Spring MVC开发Web系统时,经常需要在处理请求时使用request对象,比如获取客户端ip地址.请求的url.header中的属性(如cookie.授权信息).body中的数据等.由于在Spring MVC中,处理请求的Controller.Service等对象都是单例的,因此获取request对象时最需要注意的问题,便是

HashMap\HashTable\ConcurrentHashMap的原理与区别

HashTable: 底层数组+链表,key与value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低. 初始size为11,扩容:newsize = oldsize*2 + 1 计算index的方法:index = (hash & 0x7FFFFFFF)%tab.length HashMap: 底层数组+链表实现,可以存储null键和null值,线程不安全 初始size为16,扩容newsize = oldsize*2,size一定为2的n次幂

HhashMap HashTable ConcurrentHashMap

hashMap hashTable concurrentHashMap hashMap的效率高于hashTable,hashMap是线程不安全的,并发时hashMap put方法容易引起死循环,导致cpu利用率达到100% 所以高并发下不能使用hashMap,而是用ConcurentHashMap,则不会出现这种情况

一天一个设计模式——(Singleton)单例模式(线程安全性)

一.模式说明 有时候,我们希望在应用程序中,仅生成某个类的一个实例,这时候需要用到单例模式. 二.模式类图 三.模式中的角色 Singleton角色,该模式中仅有的一个角色,该角色有一个返回唯一实例的getInstance方法,该方法总是返回同一个实例: 四.代码示例 单例模式比较简单,要实现单例模式只需保证三点: 私有化类的构造函数: 在类中创建类的对象: 提供获取对象的公有方法: package com.designpattern.cn.singletonpattern; public cl