zoukankan      html  css  js  c++  java
  • ThreadLocal与线程池使用的问题

    感谢博主的这篇分享,见 https://www.cnblogs.com/qifenghao/p/8977378.html

    在今天的面试中,突然被考官问了这个问题,当时脱口而出的是 threadlocal容易会有内存泄漏,需要注意remove。其实自己仔细想想,这个回答太过于结果了,没有思考为何要配合线程池的时候,去remove。

    注意,这里需要你的jdk版本为1.8及以上,否者清将lambda表达式改为匿名内部类

    问题的版本

     1 public class ThreadLocalAndPool {
     2 
     3     /**
     4      * jdk8 的语法
     5      */
     6     private static ThreadLocal<Integer> variableLocal = ThreadLocal.withInitial(() -> 0);
     7 
     8     public static int get() {
     9         return variableLocal.get();
    10     }
    11 
    12     public static void remove() {
    13         variableLocal.remove();
    14     }
    15 
    16     public static void increment() {
    17         variableLocal.set(variableLocal.get() + 1);
    18     }
    19 
    20     public static void main(String[] args) {
    21         ExecutorService executorService = new ThreadPoolExecutor(2,2,0, TimeUnit.SECONDS,new LinkedBlockingDeque<>(12));
    22 
    23         for(int i=0;i<5;i++){
    24             executorService.execute(()->{
    25                 long threadId = Thread.currentThread().getId();
    26 
    27                 int before = get();
    28                 increment();
    29                 int after = get();
    30                 System.out.println("threadid " + threadId +"  before " + before + ", after " + after);
    31             });
    32         }
    33 
    34         executorService.shutdown();
    35     }
    36 
    37 
    38 }

    得到的结果

    threadid 12 before 0, after 1
    threadid 13 before 0, after 1
    threadid 12 before 1, after 2
    threadid 13 before 1, after 2
    threadid 12 before 2, after 3

    这个其实就是threadlocal与线程池使用的问题了,因为threadlocal维护是 Map<Thread,T>这个结构,而线程池是对线程进行复用的,如果没有及时的清理,那么之前对该线程的使用,就会影响到后面的线程了,造成数据不准确。

    修正的版本,就是加一个remove

     1 public class ThreadLocalAndPool {
     2 
     3     /**
     4      * jdk8 的语法
     5      */
     6     private static ThreadLocal<Integer> variableLocal = ThreadLocal.withInitial(() -> 0);
     7 
     8     public static int get() {
     9         return variableLocal.get();
    10     }
    11 
    12     public static void remove() {
    13         variableLocal.remove();
    14     }
    15 
    16     public static void increment() {
    17         variableLocal.set(variableLocal.get() + 1);
    18     }
    19 
    20     public static void main(String[] args) {
    21         ExecutorService executorService = new ThreadPoolExecutor(2,2,0, TimeUnit.SECONDS,new LinkedBlockingDeque<>(12));
    22 
    23         for(int i=0;i<5;i++){
    24             executorService.execute(()->{
    25                 try {
    26                     long threadId = Thread.currentThread().getId();
    27 
    28                     int before = get();
    29                     increment();
    30                     int after = get();
    31                     System.out.println("threadid " + threadId +"  before " + before + ", after " + after);
    32                 }
    33                 finally {
    34                     remove();
    35                 }
    36             });
    37         }
    38 
    39         executorService.shutdown();
    40     }
    41 
    42 
    43 }

    上面运行的结果如下(不同机器的threadid会有所不同)

    threadid 12 before 0, after 1
    threadid 13 before 0, after 1
    threadid 12 before 0, after 1
    threadid 13 before 0, after 1
    threadid 13 before 0, after 1

  • 相关阅读:
    自动化测试之读取配置文件 | 踩坑指南
    文未有福利 | BAT 名企大厂做接口自动化如何高效使用 Requests ?
    高效能 Tester 必会的 Python 测试框架技巧
    移动自动化测试从入门到高级实战
    1 天,1000+ 测试工程师分享了这个课程 | 年度福利
    H5性能分析实战来啦~
    接口测试实战 | Android 高版本无法抓取 HTTPS,怎么办?
    实战 | 接口自动化测试框架开发(Pytest+Allure+AIOHTTP+用例自动生成)
    第一期线上沙龙PPT领取方式
    Java日志第48天 2020.8.24
  • 原文地址:https://www.cnblogs.com/westlin/p/10645217.html
Copyright © 2011-2022 走看看