zoukankan      html  css  js  c++  java
  • Collections.synchronizedSortedMap的 iterator 遍历时候的线程安全问题

    ConcurrentHashMap 在 iterator 遍历时候的是线程安全 的,Collections.synchronizedSortedMap 不是;

    package test.lk;
    
    import com.google.common.cache.CacheBuilder;
    import com.google.common.cache.CacheLoader;
    import com.google.common.cache.LoadingCache;
    import lombok.SneakyThrows;
    import org.apache.tomcat.util.modeler.ManagedBean;
    
    import java.util.*;
    import java.util.concurrent.CopyOnWriteArrayList;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.TimeUnit;
    
    /**
     * redis工具类
     *  
     * @version [版本号, 2016年7月27日]
     * @see [相关类/方法]
     * @since [产品/模块版本]
     */
    public final class TestColl {
    
    
        private SortedMap<String, Object> misMatchRptMap = Collections.synchronizedSortedMap(new TreeMap<>());
    
        public static void main(String[] args) {
            test1();
        }
    
    
        @SneakyThrows
        public static void main2(String[] args) {
            LoadingCache<String, String> cache = CacheBuilder.newBuilder()
                    .maximumSize(5)
                    .expireAfterWrite(10, TimeUnit.MINUTES)
                    .build(new CacheLoader<String, String>() {
                        @SneakyThrows
                        @Override
                        public String load(String id) {
                            // 加载时,睡眠一秒
                            Thread.sleep(1000);
                            return id + System.currentTimeMillis();
                        }
                    });
    
            // 异步线程加载
            new Thread(() -> {
                try {
                    System.out.println("执行get");
                    cache.get("key");
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }).start();
    
            // 异步线程移除
            new Thread(() -> {
                // 睡眠,让这个线程后执行
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("执行invalidate");
                cache.invalidate("key");
            }).start();
    
            // 按程序逻辑来说,我们应该拿到的结果是空map
            Thread.sleep(1200);
            System.out.println(cache.asMap());
        }
    
    
        private static void test1() {
    
            // TreeMap Concurrent 线程安全..
            SortedMap<String, ManagedBean> misMatchRptMap = Collections.synchronizedSortedMap(new TreeMap<>());
    //
    Map<String, ManagedBean> misMatchRptMap = Collections.synchronizedMap(new HashMap<>()); 也是一样的
    //        Map<String, ManagedBean> misMatchRptMap = new ConcurrentHashMap<>();
            misMatchRptMap.put("aa", new ManagedBean()); //  类型是 Collections$SynchronizedSortedMap
            new Thread() {
                @Override
                public void run() {
                    for (int i = 0; i < Integer.MAX_VALUE; i++) {
                        misMatchRptMap.put("aa" + i, new ManagedBean());
                        try {
                            Thread.sleep(2);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                    }
                }
            }.start();
    
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
    
                    // 虽然entries 是线程安全的,但是
                    // 这里的iterator 不是Concurrent, 而是TreeMap 的 而是而是TreeMap的内部类: TreeMap.iterator
                    Set<Map.Entry<String, ManagedBean>> entries = misMatchRptMap.entrySet(); // 虽然TreeMap 的entrySet 是线程安全的Collections$SynchronizedSet , 但是entrySet 的iterator 并不是
                    for (Iterator<Map.Entry<String, ManagedBean>> iterator = entries.iterator(); iterator.hasNext(); ) {
                        Map.Entry<String, ManagedBean> next =  iterator.next();// TreeMap$EntryIterator; 因为 Collections$SynchronizedSet 没有重写iterator 方法,没有提供线程安全的iterator , 这里会报错
                        System.out.println("next = " + next);
                        iterator.remove();
                    }
                }
            }, 100, 5);
        }
    
        private static void test13() {
            List<String> list = new CopyOnWriteArrayList<>();//  "Timer-0" java.lang.UnsupportedOperationException   at java.util.concurrent.CopyOnWriteArrayList$COWIterator.remove(CopyOnWriteArrayList.java:1176)
            list.add("111");
            list.add("222");
            list.add("333");
    
            new Thread() {
                @Override
                public void run() {
                    for (int i = 0; i < Integer.MAX_VALUE; i++) {
                        list.add(" ele " + i);
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                    }
                }
            }.start();
    
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){
                        String ele=iterator.next();
                        System.out.println("ele = " + ele);
                        iterator.remove();
                    }
                    System.out.println(list);
                }
            }, 100, 1000);
        }
    
        private static void test2() {
            List<String> list = new ArrayList<>();
            list.add("111");
            list.add("222");
            list.add("333");
    
            new Thread() {
                @Override
                public void run() {
                    for (int i = 0; i < Integer.MAX_VALUE; i++) {
                        list.add(" ele " + i);
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                    }
                }
            }.start();
    
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){
                        String ele=iterator.next();
                        System.out.println("ele = " + ele);
                        iterator.remove();
                    }
                    System.out.println(list);
                }
            }, 100, 1000);
        }
    
    }

     为什么呢?

    一般的经验是,我使用iterator.remove(); 就可以保证不会报错了吧。

    但是呢,iterator.remove(); 方法却并不能保证线程安全! 没有谁说 iterator.remove() 在多线程并发执行的情况下一定不报错! 千万不能记混哦!

    其实,

    虽然Collections.synchronizedSortedMap(new TreeMap<>()); 之后, TreeMap 的entrySet 是线程安全的Collections$SynchronizedSet , 但是entrySet 的iterator 并不是。

    而 ConcurrentHashMap 里面存在大量子类, 重写了大部分的 集合相关的接口、类,确保了所有的集合操作、遍历都是线程安全的!


    版权声明
    本文原创发表于 博客园,作者为 阿K .     本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
    欢迎关注本人微信公众号:觉醒的码农,或者扫码进群:

  • 相关阅读:
    学生管理系统
    Selenium元素定位的30种方式
    python-- 多进程
    python 多线程的实现
    python 节省内存的for循环技巧
    python 生成器
    python 字符串编码检测
    opencv-python 图片的几何变换
    opencv-python --图像处理
    目标检测
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/15341643.html
Copyright © 2011-2022 走看看