首页 > 其他分享 >Hashtable和ConcurrentHashMap如何实现线程安全

Hashtable和ConcurrentHashMap如何实现线程安全

时间:2024-04-30 11:34:51浏览次数:31  
标签:ConcurrentHashMap hash tab value 线程 Hashtable key put null

感谢一起重温此知识点的同学--糖糖

HashMap线程不安全,效率高

put方法没有锁

// 任意地方声明HashMap,点击put即可进入源码
HashMap<String,String> hashMap = new HashMap();
hashMap.put("heart","糖糖");
// HashMap.put(key,value)部分源码
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}
/**
 * HashMap.put(key,value)部分sub源码
 */
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

HashTable线程安全,效率不高

put方法上加了synchronized锁,每次put都会等锁

// 任意地方声明Hashtable,点击put即可进入源码
Hashtable<String,String> hashtable = new Hashtable();
hashtable.put("heart","糖糖");
/**
 * Hashtable.put(key,value)部分源码
 */
public synchronized V put(K key, V value) {
    // Make sure the value is not null
    if (value == null) {
        throw new NullPointerException();
    }

    // Makes sure the key is not already in the hashtable.
    Entry<?,?> tab[] = table;
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    @SuppressWarnings("unchecked")
    Entry<K,V> entry = (Entry<K,V>)tab[index];
    for(; entry != null ; entry = entry.next) {
        if ((entry.hash == hash) && entry.key.equals(key)) {
            V old = entry.value;
            entry.value = value;
            return old;
        }
    }

    addEntry(hash, key, value, index);
    return null;
}

ConcurrentHashMap线程安全,效率高

put方法内部加了分段锁(synchronized锁),Jdk1.7版本固定分为16段,Jdk1.8及以后版本改为N段

// 任意地方声明ConcurrentHashMap,点击put即可进入源码
ConcurrentHashMap<String,String> concurrentHashMap = new ConcurrentHashMap<>();
concurrentHashMap.put("heart","糖糖");
// ConcurrentHashMap.put(key,value)部分源码
public V put(K key, V value) {
    return putVal(key, value, false);
}
/**
 * ConcurrentHashMap.put(key,value)部分sub源码
 */
final V putVal(K key, V value, boolean onlyIfAbsent) {
    if (key == null || value == null) throw new NullPointerException();
    int hash = spread(key.hashCode());
    int binCount = 0;
    for (Node<K,V>[] tab = table;;) {
        Node<K,V> f; int n, i, fh;
        if (tab == null || (n = tab.length) == 0)
            tab = initTable();
        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
            if (casTabAt(tab, i, null,
                         new Node<K,V>(hash, key, value, null)))
                break;                   // no lock when adding to empty bin
        }
        else if ((fh = f.hash) == MOVED)
            tab = helpTransfer(tab, f);
        else {
            V oldVal = null;
            synchronized (f) {
                if (tabAt(tab, i) == f) {
                    if (fh >= 0) {
                        binCount = 1;
                        for (Node<K,V> e = f;; ++binCount) {
                            K ek;
                            if (e.hash == hash &&
                                ((ek = e.key) == key ||
                                 (ek != null && key.equals(ek)))) {
                                oldVal = e.val;
                                if (!onlyIfAbsent)
                                    e.val = value;
                                break;
                            }
                            Node<K,V> pred = e;
                            if ((e = e.next) == null) {
                                pred.next = new Node<K,V>(hash, key,
                                                          value, null);
                                break;
                            }
                        }
                    }
                    else if (f instanceof TreeBin) {
                        Node<K,V> p;
                        binCount = 2;
                        if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                       value)) != null) {
                            oldVal = p.val;
                            if (!onlyIfAbsent)
                                p.val = value;
                        }
                    }
                }
            }
            if (binCount != 0) {
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                if (oldVal != null)
                    return oldVal;
                break;
            }
        }
    }
    addCount(1L, binCount);
    return null;
}

标签:ConcurrentHashMap,hash,tab,value,线程,Hashtable,key,put,null
From: https://www.cnblogs.com/mjtabu/p/18167694

相关文章

  • 我的第一个套接字通信(基本多线程)....
    前排叠个甲:为什么现在才学习到Linux套接字???我的回答是:大一玩了一年,大二开始接触C++,其中呢,大二上学习完了Qt,大二下才开始接触Linux,而在这期间,反复阅读了C++的特性源码....所以。回归正题:直接放代码,没什么好说的,就那一套流程:服务器端的代码:#include<stdio.h>#include<stdlib.h>......
  • Windows下绑定线程到指定的CPU核心
    在某些场景下,需要把程序绑定到指定CPU核心提高执行效率。通过微软官方文档查询到Windows提供了两个Win32函数:SetThreadAffinityMask和SetProcessAffinityMask为指定线程和进程设置处理器关联掩码。通俗的讲就是在指定的CPU核心上执行线程或者进程。这里的CPU核心指的是逻辑核心......
  • 线程池的实现
    #include<vector>#include<thread>#include<queue>#include<functional>#include<mutex>#include<condition_variable>#include<iostream>classThreadPool{public:ThreadPool(size_tthreads):stop(false......
  • Java线程池控制线程存活时间的机制
    核心线程:永不销毁:此类线程处理完任务后,会调用任务队列的take方法,此方法是阻塞的,假如队列为空了,该线程就会被阻塞住,线程就能一直存活着了。非核心线程:空闲指定时间后,会被销毁:此类线程处理完任务后,会通过调用任务队列的pop方法,此方法接收一个时间参数且是限时阻塞的,假如队......
  • Java 线程Dump分析
    一般当服务器挂起,崩溃或者性能低下时,就需要抓取服务器的线程堆栈(ThreadDump)用于后续的分析。在实际运行中,往往一次dump的信息,还不足以确认问题。为了反映线程状态的动态变化,需要接连多次做threaddump,每次间隔10-20s,建议至少产生三次dump信息,如果每次dump都指向同一个问题,我们......
  • Slave SQL线程与PXB FTWRL死锁问题分析
    1.问题背景2.27号凌晨生产环境MySQL备库在执行备份期间出现因FLUSHTABLESWITHREADLOCK未释放导致备库复制延时拉大,慢日志内看持锁接近25分钟未释放。版本:MySQL5.7.21PXB2.4.18慢查询日志:备份脚本中的备份命令:mysql_kill.sh的主要逻辑内容:备份参数:2.问题复......
  • Python多线程编程深度探索:从入门到实战
    title:Python多线程编程深度探索:从入门到实战date:2024/4/2818:57:17updated:2024/4/2818:57:17categories:后端开发tags:多线程并发编程线程安全Python异步IO性能优化实战项目第1章:Python基础知识与多线程概念Python简介:Python是一种高级、通用、解释......
  • Java优雅关闭线程池
    一、背景:线程池中有任务正在执行,此时需要关闭或重启应用,池中的任务如何处理,需要考虑任务的损失、关闭速度两个方面考虑。推荐使用Spring提供的线程池:ThreadPoolTaskExecutor,让Spring帮我们管理线程池的生命周期,初始化、监控、扩展、关闭。特别在应用关闭、重启时能实现优雅关闭......
  • Redis单线程,为什么速度快
    Redis是单线程的,但是为什么还那么快完全基于内存的,C语言编写采用单线程,避免不必要的上下文切换可竞争条件使用多路IO复用模型,非阻塞IO例如:bgsave和bgrewriteaof都是在后台执行操作,不影响主线程的正常使用,不会产生阻塞解释一下多路IO复用模型?多路IO复用模型是指利用......
  • 线程池
    线程池1.线程池概念 2.标准库线程池(面试考点) 总结:  3.工厂类创建线程池和基本使用查看代码importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;classTest{publicstaticvoidmain(String[]args){......