• 【深入Java基础】HashMap的高级用法(二):同步


    HashMap的高级用法:同步

    HashMap是不支持同步的,不能用于多线程中。而HashTable是同步的,这个日后再论。我们可以使用以下两种方法来实现HashMap的同步:

    • 使用ConcurrentHashMap

    • 使用Collections.synchronizedMap获取同步map

    使用ConcurrentHashMap

        ConcurrentHashMap<Integer,String> concurrentHashMap = new ConcurrentHashMap<>();

    使用Collections.synchronizedMap获取同步map

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

    测试

    对于没有同步的HashMap在多线程中运行一定会抛出异常:

        java.util.ConcurrentModificationException

    运行两个线程同时对一个hashmap进行读写操作:

        HashMap<Integer,String> hashMap1 = new HashMap<>();
            //写线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 1000; i++) {
                        hashMap1.put(i,"value"+i);
                        try {
                            Thread.sleep(new Random().nextInt(10));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            //读线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        if (hashMap1.size() > 0) {
                            for (Map.Entry entry : hashMap1.entrySet()) {
                                System.out.println(entry.getKey() + "=" + entry.getValue());
                            }
                        }
                        try {
                            Thread.sleep(new Random().nextInt(10));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();

    运行以上代码抛出异常java.util.ConcurrentModificationException。原因是未实现同步时,在迭代hashmap的时候不能修改数据。

    Collections.synchronizedMap实现同步:

        HashMap<Integer,String> hashMap1 = new HashMap<>();
            Map<Integer, String> map = Collections.synchronizedMap(hashMap1);
            //写线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 1000; i++) {
                        map.put(i,"value"+i);
                        try {
                            Thread.sleep(new Random().nextInt(10));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            //读线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        if (map.size() > 0) {
                            for (Map.Entry entry : map.entrySet()) {
                                System.out.println(entry.getKey() + "=" + entry.getValue());
                            }
                        }
                        try {
                            Thread.sleep(new Random().nextInt(10));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();

    运行以上代码任然抛出异常java.util.ConcurrentModificationException。可见该方法并不安全。(还是这样测试有问题?)

    ConcurrentHashMap实现同步:

          ConcurrentHashMap<Integer,String> concurrentHashMap = new ConcurrentHashMap<>();
           //写线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 1000; i++) {
                        concurrentHashMap.put(i,"value"+i);
                        try {
                            Thread.sleep(new Random().nextInt(10));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            //读线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        if (concurrentHashMap.size() > 0) {
                            for (Map.Entry entry : concurrentHashMap.entrySet()) {
                                System.out.println(entry.getKey() + "=" + entry.getValue());
                            }
                        }
                        try {
                            Thread.sleep(new Random().nextInt(10));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();

    运行以上代码,无异常。

    所以为了保证多线程下的hashmap的数据一致性使用ConcurrentHashMap最为合理。并且ConcurrentHashMap的效率也比较高。为什么日后再论。

    使用lock锁手动实现hashmap的同步:

         ReentrantLock lock = new ReentrantLock(true);
         HashMap<Integer, String> hashMap1 = new HashMap<>();
    
                //写线程
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                        for (int i = 0; i < 1000; i++) {
                            hashMap1.put(i, "value" + i);
                            try {
                                Thread.sleep(new Random().nextInt(10));
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        } catch (Exception e) {
    
                        } finally {
                            //lock.unlock();
                        }
                    }
                }).start();
    
    
            //读线程
            new Thread(new Runnable() {
                @Override
                public void run() {
    
                    while (true) {
                        lock.lock();
                        try {
                            if (hashMap1.size() > 0) {
                                for (Map.Entry entry : hashMap1.entrySet()) {
                                    System.out.println(entry.getKey() + "=" + entry.getValue());
                                }
                            }
                        } catch (Exception e) {
                            System.out.println(e.getMessage());
                        } finally {
                            lock.unlock();
                        }
    
    
                        try {
                            Thread.sleep(new Random().nextInt(10));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
  • 相关阅读:
    WinPE U盘安装原版Win10系统详细教程
    Foxmail for windows 客户端设置和 IMAP、POP3/SMTP 的设置
    微信打开X5调试,使微信页面可以在谷歌浏览器调试
    古今时辰对照表--选择吉日吉时,养生时辰必看
    2020爱你爱你,新的一年,新的开始,2020我想对你说
    人民日报推荐好文《善待你所在的单位》
    致大学生,我把私藏多年的的实用工具/学习网站都贡献出来了~~
    使用poco 的NetSSL_OpenSSL 搭建https 服务端,使用C++客户端,java 客户端访问,python访问(python还没找到带证书访问的代码.)
    C++ activemq CMS 学习笔记.
    关于 Poco::TCPServer框架 (windows 下使用的是 select模型) 学习笔记.
  • 原文地址:https://www.cnblogs.com/cnsec/p/13286733.html
Copyright © 2020-2023  润新知