Map、list 线程安全问题

什么叫做线程安全?
单线程和多线程执行的结果总是唯一的。
一、HashMap解析

HashMap是线程不安全的,多线程情况下不推荐使用HashMap。它的key,value运行为null
二、Hashtable解析

Hashtable在jdk1.1就有了,那么它是怎样实现线程安全的呢?主要看put、remove、get方法猜它肯定进行的同步控制的。于是看源码:

//get它搞成了同步方法,保证了get的安全性
 public synchronized V get(Object key) {
       ……
    }

//synchronized,同样
public synchronized V put(K key, V value) {
       ……
    }
//也是搞成了同步方法
public synchronized V remove(Object key) {
     ……
    }

所以为什么Hashtable是线程安全的,因为它的remove,put,get做成了同步方法,保证了Hashtable的线程安全性。

每个操作数据的方法都进行同步控制之后,由此带来的问题任何一个时刻只能有一个线程可以操纵Hashtable,所以其效率比较低。
三、Collections.synchronizedMap()解析

我们看源码:

  public int size() {
            synchronized (mutex) {return m.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return m.isEmpty();}
        }
        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);}
        }

        public V put(K key, V value) {
            synchronized (mutex) {return m.put(key, value);}
        }
        public V remove(Object key) {
            synchronized (mutex) {return m.remove(key);}
        }
        public void putAll(Map<? extends K, ? extends V> map) {
            synchronized (mutex) {m.putAll(map);}
        }
        public void clear() {
            synchronized (mutex) {m.clear();}
        }

   

我们惊人的发现,synchronizedMap只是将HashMap的操纵放在了同步代码块中来保证SynchronizedMap的线程安全性。因此,SynchronizedMap也可以允许key和value为null。这样带来的问题也是任何一个时刻只能有一个线程可以操纵synchronizedMap,所以其效率比较低。

同样,Collections下的SynchronizedXX也是用同样方法实现线程安全性的。如SynchronizedSortedMap
四、ConcurrentHashMap

为什么ConcurrentHashMap可以多线程访问呢?是因为ConcurrentHashMap将Map分段了,每个段进行加锁,而不是想Hashtable,SynchronizedMap是整个map加锁,这样就可以多线程访问了。
如图:
 

ConcurrentHashMap默认运行16个线程同时访问该map。但是我们可以通过一个函数来设置增加或减少最大可运行访问的线程数目。

//就是这个concurrencyLevel
public ConcurrentHashMap(int initialCapacity,
                             float loadFactor, int concurrencyLevel)

 

所以就有了下面这几个问题:
(1) 多线程可以同时写一个ConcurrentHashMap的分段吗?

    不行。分段就像一个单独的HashMap,只允许一个线程向其写入数据

(2)多个线程可以同时写入不同分段吗?

    这当然可以咯!

(3)多个线程可以同时从一个分段中读数据吗?

    可以

(4)如果一个线程正在向一个分段写入数据,其他线程可以从该分段中读取数据吗?

    可以。但是读取到最后更新的数据。

最后需要注意的一点是CoucrrentHashMap是不允许key和vlaue为null的。
六、ArrayList为什么是线程不安全的,Vector是线程安全的?

Vector肯定是做了同步控制了的。看源码

//同步方法
 public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }
//同步方法
public synchronized boolean removeElement(Object obj) {
        modCount++;
        int i = indexOf(obj);
        if (i >= 0) {
            removeElementAt(i);
            return true;
        }
        return false;
    }

所以Vector也是用同步方法的方式来保证线程安全的。

知识点:

我们知道 java.util.HashMap 不是线程安全的,因此如果在使用迭代器的过程中有其他线程修改了map,那么将抛出 ConcurrentModificationgException,这就是所谓 fail-fast 策略

fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast 事件。
 

若在多线程环境下使用 fail-fast机制的集合,建议使 “java.util.concurrent 包下的类” 去取代 “java.util 包下的类”。

 

hashMap 无序

treeMap  按照数字从小到大的顺序 或者字母顺序,先入不一定先出。

 

linkedhashMap 按照放入的顺序,先入先出。
 

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用\[1\]中提到,在实现线程安全map时,作者选择使用了RWLock来控制map对象的访问。RWLock将线程对资源的访问分为读取操作和写入操作两类,允许多个线程进行读取操作,但只允许一个线程进行写入操作。这样做的目的是为了提高效率,避免每个线程都独占访问导致的性能下降。 根据这个实现,可以说std::map在多线程同时进行读取操作时是安全的。因为多个线程进行读取操作时,不会相互阻塞,而是可以同时进行。只有在有线程进行写入操作时,其他线程才会被阻塞,等待写入操作结束。 引用\[2\]和\[3\]中提到了作者在实现中使用了std::map来记录线程的锁状态。这表明作者在实现中考虑了多线程对map的并发访问问题,并采取了相应的措施来保证线程安全。 综上所述,根据作者的实现方式,std::map在多线程同时进行读取操作时是安全的。但需要注意的是,如果有写入操作存在,读取操作会被阻塞,直到写入操作完成。 #### 引用[.reference_title] - *1* [C++11:基于std::unordered_map和共享锁构建线程安全map](https://blog.csdn.net/10km/article/details/52072061)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [基于std::map实现的线程安全map以及测试](https://blog.csdn.net/chiefarbiter/article/details/90217542)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值