• 第五章:(2)HashSet 集合线程不安全&解决方案


    一、HasheSet 集合的不安全

      1、故障现象

    public class NotSafeSetDemo {
        public static void main(String[] args) {
            Set<String> set = new HashSet<>();
    
            for (int i = 0; i < 30; i++) {
                new Thread(() -> {
                    //向集合添加内容
                    set.add(UUID.randomUUID().toString().substring(0, 8));
                    //从集合获取内容
                    System.out.println(set);
                }, String.valueOf(i)).start();
            }
        }
    }

      运行结果:

      

      2、分析

      (1)HashSet 是线程不安全的
      (2)HashSet 的底层是一个 HashMap(),但是这个 HashMap 的 value 永远是一个 Object 类型的常量(PRESENT),但HashSet的add是放一个值(调用map的PUT方法),而HashMap是放K、V键值对
    public HashSet() {
        map = new HashMap<>();
    }
     
    private static final Object PRESENT = new Object();
     
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

        因为底层使用的是 HashMap,而 HashMap 也是线程不安全的,并且 HashSet 的 add 方法也没有使用 synchronized 同步锁。

    二、方案一

      1、使用 Collections 工具类

      Collections 工具类也提供了线程安全的 Set 集合。

      2、代码实现

    public class SafeSetDemo {
    
        public static void main(String[] args) {
            Set<String> set = Collections.synchronizedSet(new HashSet<>());
    
            for (int i = 0; i < 30; i++) {
                new Thread(() -> {
                    //向集合添加内容
                    set.add(UUID.randomUUID().toString().substring(0, 8));
                    //从集合获取内容
                    System.out.println(set);
                }, String.valueOf(i)).start();
            }
        }
    }

    三、方案二

      1、使用 CopyOnWriteArraySet 

        原理同 CopyOnWriteArrayList。

      2、代码实现

    public class SafeSetDemo {
    
        public static void main(String[] args) {
    
            Set<String> set = new CopyOnWriteArraySet<>();
            for (int i = 0; i < 30; i++) {
                new Thread(() -> {
                    //向集合添加内容
                    set.add(UUID.randomUUID().toString().substring(0, 8));
                    //从集合获取内容
                    System.out.println(set);
                }, String.valueOf(i)).start();
            }
        }
    }
  • 相关阅读:
    windows 安装 nodejs指定版本
    Xshell通过ssh登录远程服务器(秘钥)
    CentOS7 防火墙操作
    Linux系统MySQL开启远程连接
    PHP 下载图片文件并压缩文件成zip
    thinkphp 中更新数据字段,同时某字段值++操作(报错TP5.1不支持的数据表达式:[exp]的解决办法)
    layui的loading加载中
    Linux下面安装swoole
    windows 下cmd命令删除文件或者文件夹
    PHP 删除某目录下的全部文件
  • 原文地址:https://www.cnblogs.com/niujifei/p/15828423.html
Copyright © 2020-2023  润新知