zoukankan      html  css  js  c++  java
  • [集合]线程安全的HashMap

     一、一般模式下线程安全的HashMap

      默认情况常用的HashMap都是线程不安全的,在多线程的环境下使用,常常会造成不可预知的,莫名其妙的错误。那么,我们如何实现一个线程安全的HashMap呢?其中一个可行的方式是使用Collectons.synchronizedMap() 方法来包装我们的HashMap。如下:

    Map<String, String> map = Collections.synchronizedMap(new HashMap<String,String>());

      

    Collections.synchronizedMap()会生成一个SynchronizedMap,它使用委托模式,将自己HashMap相关的功能交给传入HashMap实现,二自己负责线程安全的相关实现,下面看看
    SynchronizedMap的定义:
        private static class SynchronizedMap<K,V>
            implements Map<K,V>, Serializable {
            private static final long serialVersionUID = 1978198479659022715L;
    
            private final Map<K,V> m;     // Backing Map
    
            // 使用 mutex 实心对 map 的互斥操作
            final Object      mutex;        // Object on which to synchronize
    
            SynchronizedMap(Map<K,V> m) {
                this.m = Objects.requireNonNull(m);
                mutex = this;
            }

      如在代码中看到的,所有对Map的操作都需要用 这个 mutex  来同步,以实现线程安全。比如说下面这些常见的对HashMap的操作方法:

            public boolean containsKey(Object key) {
                synchronized (mutex) {return m.containsKey(key);}
            }
            public boolean containsValue(Object value) {
                synchronized (mutex) {return m.containsValue(value);}
            }
            public V get(Object key) {
                synchronized (mutex) {return m.get(key);}
            }

      除了以上看到的方法之外,其他的Map相关的方法有类似的操作。虽然这个包装的Map可以实现线程安全的要求,但是,它在多线程环境下的性能表现并不是很好,无论是对Map的读取还是写入,偶数需要获得 mutex 的同步锁,这会导致所有对Map的安全操作也会进入等待状态,知道mutex可用。 如果并发级别不高,那么这个 包装的Map可以基本满足要求,但是在搞并发的环境中,我们需要寻找新的解决方案。 ——---> 那就是我们的 ConcurrentHashMap.

     二、提高"锁"性能的策略

      1. 减少锁的持有时间

        只在必要时进行同步,减少锁的持有时间。比如说在一个方法中只有一个变量需要同步,那么就没有必要对这整个方法都进行同步,而只需要同步这个变量即可。

            // 无谓的加锁时间
            public synchronied void syncMethod() {
    
                    othrerMethod();
                    mutexMethod();
                    otherMethod();
            }
    
            // 正确的加锁时间
            public  void syncMethod() {
    
                    othrerMethod();
                    synchronied(this){
                    mutexMethod();
                    }
                    otherMethod();
            }

      2.  减小锁的粒度

        在获取全局信息方法不频繁的时候,通过减小锁的粒度可以搞系统的吞吐量。

      3. 读写分离锁替换独占锁

        在读都写少的情况下,使用读写分离锁,多线程读时不阻塞,而只对写线程进行同步。

      4. 锁分离

        对不同功能的锁进行不同的锁策略。

      5. 锁粗化

        系统对于"锁"的调度也是需要性能消耗的,又是我们可以适当的加大锁的范围,比如说在循环中尽量减少对锁的请求和释放,而是在得到锁的情况,一次性把问题解决。

      

  • 相关阅读:
    解决端口被占用
    Oracle查询所有表的字段明细
    Spring cron表达式
    Java爬取12306余票
    Activiti工作流框架——快速上手
    ERROR 1045 (28000): Access denied for user 'xxx'@'localhost' (using password: YES)【奇葩的bug】
    一分钟学会JavaMail(假)__手动滑稽
    通过Servlet实现汉字验证码
    使用ServletContext对象读取资源文件
    编写一个简单的java服务器程序
  • 原文地址:https://www.cnblogs.com/ytuan996/p/10585633.html
Copyright © 2011-2022 走看看