证明Hashmap线程不安全

 线程不安全的表现

hashMap出现线程不安全的表现:
表现1:

多个线程同时操作一个hashmap就可能出现不安全的情况:
比如A B两个线程(A线程获数据 B线程存数据) 同时操作myHashMap
1.B线程执行存放数据
modelHashMap.put("1","2");
2.A线程执行get获取数据
modelHashMap.get("1")
A线程获取的值本来应该是2,但是如果A线程在刚到达获取的动作还没执行的时候,
线程执行的机会又跳到线程B,此时线程B又对modelHashMap赋值 如:modelHashMap.put("1","3");
然后线程虚拟机又执行线程A,A取到的值为3,这样map中第一个存放的值 就会丢失。。。。。

要保证值的准确,就要保证操作的原子性,就是保证A操作从头开始不能被打断。。所有要用同步关键字,或者使用java 1.5中的current新包中的ConcurrentHashMap,这是线程安全的,在java最新的并发包中,对之前非线程安全的工具,如hashMap List 都做了同步封转。
表现2:

一般我们声明HashMap时,使用的都是默认的构造方法:HashMap<K,V>,看了代码你会发现,它还有其它的构造方法:HashMap(int initialCapacity, float loadFactor),其中参数initialCapacity为初始容量,loadFactor为加载因子,而之前我们看到的threshold = (int)(capacity * loadFactor); 如果在默认情况下,一个HashMap的容量为16,加载因子为0.75,那么阀值就是12,所以在往HashMap中put的值到达12时,它将自动扩容两倍,如果两个线程同时遇到HashMap的大小达到12的倍数时,就很有可能会出现在将oldTable转移到newTable的过程中遇到问题,从而导致最终的HashMap的值存储异常。
表现3:

构造entry<K,V>单链表时,也会出现不安全的情况。


代码实例

package com.echemi.api.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class HashMapTest2 {
     static void doit() throws Exception{
        final int count = 200;
        final AtomicInteger checkNum = new AtomicInteger(0);
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(100);
        //
        final Map<Long, String> map = new HashMap<Long, String>();
         map.put(0L, "test");
        //map.put(1L, "www.imxylz.cn");
        for (int j = 0; j < count; j++) {
            newFixedThreadPool.submit(new Runnable() {
                public void run() {
                    map.put(System.nanoTime()+new Random().nextLong(), "test");
                    String obj = map.get(0L);
                     if (obj == null) {
                         checkNum.incrementAndGet();
                     }
                 }
             });
        }
        newFixedThreadPool.awaitTermination(1, TimeUnit.SECONDS);
        newFixedThreadPool.shutdown();
        
        System.out.println(checkNum.get());
     }
     
     public static void main(String[] args) throws Exception{
         for(int i=0;i<10;i++) {
            doit();
             Thread.sleep(500L);
         }
     }
 }

结果一定会输出0么?结果却不一定。比如某一次的结果是:

8
0
0
1
0
0
6
5
5
0

其实出现这个问题是因为HashMap在扩容是导致了重新进行hash计算。

如果把Hashmap 换成 Hashtable 或者concurrenthashmap 就不会出现这样的问题 执行结果都会变为0

final Hashtable<Long, String> map = new Hashtable<Long, String>();
final ConcurrentHashMap<Long, String> map = new ConcurrentHashMap<Long, String>();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值