• 并发工具类库使用的常见问题


    一、ThreadLocal在多线程环境中没有清理

    由于ThreadLocal是和线程绑定的,如果线程被复用了,也即使用了线程池,那么ThreadLocal中的值是可能被复用的,这个特性如果是开发者没有预料到的,那么会产生很大的问题。例如,在JAVA web应用中,我们通常会使用很多ThreadLocal来保存一次请求的不同上下文信息,其中就包含登录用户,如果一次请求完成后,没有清理掉当前登录用户信息,那么当另外一个用户的请求进来,就会使用上一个用户,如果是涉及到数据写入,将直接导致数据错乱,造成严重生产问题。

    二、ConcurrentHashMap使用的问题

    ConcurrentHashMap提供的能力是保证单个操作在多线程环境下是安全的。如果有一段逻辑是先读取size大小,在决定是否往map里put(),那么这段逻辑必然产生并发问题。因为错误理解的ConcurrentHashMap的能力。解决办法是用加锁的方式控制并发。

    三、CopyOnWriteArrayList使用的问题

    CopyOnWrite 是一个常用的技术,Linux、Redis中都用到了。在 Java 中,CopyOnWriteArrayList 虽然是一个线程安全的 ArrayList,但因为其实现方式是,每次修改数据时都会复制一份数据出来,所以有明显的适用场景,即读多写少或者说希望无锁读的场景。

    1. //测试并发写的性能
    2. @GetMapping("write")
    3. public Map testWrite() {
    4. List<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
    5. List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<>());
    6. StopWatch stopWatch = new StopWatch();
    7. int loopCount = 100000;
    8. stopWatch.start("Write:copyOnWriteArrayList");
    9. //循环100000次并发往CopyOnWriteArrayList写入随机元素
    10. IntStream.rangeClosed(1, loopCount).parallel().forEach(__ -> copyOnWriteArrayList.add(ThreadLocalRandom.current().nextInt(loopCount)));
    11. stopWatch.stop();
    12. stopWatch.start("Write:synchronizedList");
    13. //循环100000次并发往加锁的ArrayList写入随机元素
    14. IntStream.rangeClosed(1, loopCount).parallel().forEach(__ -> synchronizedList.add(ThreadLocalRandom.current().nextInt(loopCount)));
    15. stopWatch.stop();
    16. log.info(stopWatch.prettyPrint());
    17. Map result = new HashMap();
    18. result.put("copyOnWriteArrayList", copyOnWriteArrayList.size());
    19. result.put("synchronizedList", synchronizedList.size());
    20. return result;
    21. }
    22. //帮助方法用来填充List
    23. private void addAll(List<Integer> list) {
    24. list.addAll(IntStream.rangeClosed(1, 1000000).boxed().collect(Collectors.toList()));
    25. }
    26. //测试并发读的性能
    27. @GetMapping("read")
    28. public Map testRead() {
    29. //创建两个测试对象
    30. List<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
    31. List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<>());
    32. //填充数据
    33. addAll(copyOnWriteArrayList);
    34. addAll(synchronizedList);
    35. StopWatch stopWatch = new StopWatch();
    36. int loopCount = 1000000;
    37. int count = copyOnWriteArrayList.size();
    38. stopWatch.start("Read:copyOnWriteArrayList");
    39. //循环1000000次并发从CopyOnWriteArrayList随机查询元素
    40. IntStream.rangeClosed(1, loopCount).parallel().forEach(__ -> copyOnWriteArrayList.get(ThreadLocalRandom.current().nextInt(count)));
    41. stopWatch.stop();
    42. stopWatch.start("Read:synchronizedList");
    43. //循环1000000次并发从加锁的ArrayList随机查询元素
    44. IntStream.range(0, loopCount).parallel().forEach(__ -> synchronizedList.get(ThreadLocalRandom.current().nextInt(count)));
    45. stopWatch.stop();
    46. log.info(stopWatch.prettyPrint());
    47. Map result = new HashMap();
    48. result.put("copyOnWriteArrayList", copyOnWriteArrayList.size());
    49. result.put("synchronizedList", synchronizedList.size());
    50. return result;
    51. }

  • 相关阅读:
    C++ 中的 模板类 简介
    Matlab基本语法(二)
    基于6G的联邦学习部署和应用
    [杂记]C++中移动语义与完美转发的一些理解
    基于容器和集群技术的数据自动化采集设计和实现
    用 HarmonyOS 做一个可以手势控制的电子相册应用(ArkTS)
    [附源码]Python计算机毕业设计Django网上电影购票系统
    代码随想录算法训练营第五十二天|123.买卖股票的最佳时机III、188.买卖股票的最佳时机IV
    vue3 canvas验证码和滑块拼图验证
    linux内核源码分析 - nvme设备的初始化
  • 原文地址:https://blog.csdn.net/tales522/article/details/133612237