• Map容器线程安全问题


    一、HashMap在非线程安全的环境下使用会出现什么样的问题?

    public class HashMapMultiThread {  
        static Map<String,String> map = new HashMap<String,String>();  
        public static class AddThread implements Runnable{  
            int start = 0 ;  
            public AddThread(int start){  
                this.start = start;  
            }  
            @Override    
            public void run() {  
                for (int i = 0; i < 100000; i+=2) {  
                    map.put(Integer.toString(i), Integer.toBinaryString(i));  
                      
                }  
            }  
        }  
          
        public static void main(String[] args) throws InterruptedException {  
              
            Thread t1 = new Thread(new HashMapMultiThread.AddThread(0));  
            Thread t2 = new Thread(new HashMapMultiThread.AddThread(1));  
            t1.start();  
            t2.start();  
            t1.join();  
            t2.join();  
            System.out.println(map.size());  
        }  
    }  

    上述代码使用t1和t2两个线程同时对HashMap进行put()操作,如果一切正常,我们期望得到的map.size()就是100000.但实际上,你可能会得到以下三种情况(注意,这里使用JDK7进行试验): 

    第一:程序正常结束,并且结果也是符合预期的。HashMap的大小为100000.

    第二:程序正常结束,但结果不符合预期,而是一个小于100000的数字,比如98868.

    第三:程序永远无法结束。并发形成循环链表,导致死循环。

    二、ConcurrentHashMap不能解决所有线程安全问题

    对于ConcurrentHashMap,如果只调用get或put方法是线程安全的,但你调用get后再调用put之前,如果有另一个线程也调用了put就很可能把前面的操作结果覆盖了,因为违反了原则操作的规则。此时可用putIfAbsent方法代替。如下面的例子

    public class ConcurrentHashMapTest {
    
        private static final ConcurrentMap<String, AtomicInteger> CACHE_MAP = new ConcurrentHashMap<>();
        private static final String KEY = "test";
    
        private static class TestThread implements Runnable{
            @Override
            public void run() {
                if(CACHE_MAP.get(KEY)==null){
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    CACHE_MAP.put(KEY, new AtomicInteger());
                }
                CACHE_MAP.get(KEY).incrementAndGet();
            }
        }
    
        public static void main(String[] args) {
            new Thread(new TestThread()).start();
            new Thread(new TestThread()).start();
            new Thread(new TestThread()).start();
            try {
                Thread.sleep(800);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("次数:"+CACHE_MAP.get(KEY).get());
        }
    }
  • 相关阅读:
    索引法则--少用OR,它在连接时会索引失效
    索引法则--LIKE以%开头会导致索引失效进而转向全表扫描(使用覆盖索引解决)
    索引法则--字符串不加单引号会导致索引失效
    索引法则--IS NULL, IS NOT NULL 也无法使用索引
    tomcat管理模块报401 Unauthorized
    MySQL报Too many connections
    JDBC连接MySql例子
    linux安装jdk并设置环境变量(看这一篇文章即可)
    深度解析Java可变参数类型以及与数组的区别
    MySQL真正的UTF-8字符集utf8mb4
  • 原文地址:https://www.cnblogs.com/doit8791/p/9074829.html
Copyright © 2020-2023  润新知