ThreadLocal与线程池使用的问题
感谢博主的这篇分享,见 https://www.cnblogs.com/qifenghao/p/8977378.html
在今天的面试中,突然被考官问了这个问题,当时脱口而出的是 threadlocal容易会有内存泄漏,需要注意remove。其实自己仔细想想,这个回答太过于结果了,没有思考为何要配合线程池的时候,去remove。
注意,这里需要你的jdk版本为1.8及以上,否者清将lambda表达式改为匿名内部类
问题的版本
public class ThreadLocalAndPool {
/**
* jdk8 的语法
*/
private static ThreadLocal<Integer> variableLocal = ThreadLocal.withInitial(() -> 0);
public static int get() {
return variableLocal.get();
}
public static void remove() {
variableLocal.remove();
}
public static void increment() {
variableLocal.set(variableLocal.get() + 1);
}
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(2,2,0, TimeUnit.SECONDS,new LinkedBlockingDeque<>(12));
for(int i=0;i<5;i++){
executorService.execute(()->{
long threadId = Thread.currentThread().getId();
int before = get();
increment();
int after = get();
System.out.println("threadid " + threadId +" before " + before + ", after " + after);
});
}
executorService.shutdown();
}
}
得到的结果
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
public class ThreadLocalAndPool {
/**
* jdk8 的语法
*/
private static ThreadLocal<Integer> variableLocal = ThreadLocal.withInitial(() -> 0);
public static int get() {
return variableLocal.get();
}
public static void remove() {
variableLocal.remove();
}
public static void increment() {
variableLocal.set(variableLocal.get() + 1);
}
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(2,2,0, TimeUnit.SECONDS,new LinkedBlockingDeque<>(12));
for(int i=0;i<5;i++){
executorService.execute(()->{
try {
long threadId = Thread.currentThread().getId();
int before = get();
increment();
int after = get();
System.out.println("threadid " + threadId +" before " + before + ", after " + after);
}
finally {
remove();
}
});
}
executorService.shutdown();
}
}
上面运行的结果如下(不同机器的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
ThreadLocal与线程池使用的问题的更多相关文章
- ThreadLocal遇到线程池时, 各线程间的数据会互相干扰, 串来串去
最近遇到一个比较隐蔽而又简单地问题,在使用ThreadLocal时发现出现多个线程中值串来串去,排查一番,确定问题为线程池的问题,线程池中的线程是会重复利用的,而ThreadLocal是用线程来做Ke ...
- 当ThreadLocal碰上线程池
ThreadLocal使用 ThreadLocal可以让线程拥有本地变量,在web环境中,为了方便代码解耦,我们通常用它来保存上下文信息,然后用一个util类提供访问入口,从controller层到s ...
- ThreadLocal,LinkedBlockingQueue,线程池 获取数据库连接2改进
package com.ctl.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQL ...
- Java线程池进阶
线程池是日常开发中常用的技术,使用也非常简单,不过想使用好线程池也不是件容易的事,开发者需要不断探索底层的实现原理,才能在不同的场景中选择合适的策略,最大程度发挥线程池的作用以及避免踩坑. 一.线程池 ...
- 0041 Java学习笔记-多线程-线程池、ForkJoinPool、ThreadLocal
什么是线程池 创建线程,因为涉及到跟操作系统交互,比较耗费资源.如果要创建大量的线程,而每个线程的生存期又很短,这时候就应该使用线程池了,就像数据库的连接池一样,预先开启一定数量的线程,有任务了就将任 ...
- 线程池与Threadlocal
线程池与Threadlocal 线程池: 线程池是为了使线程能够得到循环的利用,线程池里面养着一些线程,有任务需要使用线程的时候就往线程池里抓线程对象出来使用.线程池里的线程能够重复使用,所以在资源上 ...
- ThreadLocal 遇上线程池的问题及解决办法
ThreadLocal 称为线程本地存储,它为每一个使用它的线程提供一个其值(value)的副本.可以将 ThreadLocal<T> 理解成 Map<Thread, T>,即 ...
- ThreadLocal 定义,以及是否可能引起的内存泄露(threadlocalMap的Key是弱引用,用线程池有可能泄露)
ThreadLocal 也可以跟踪一个请求,从接收请求,处理请求,到返回请求,只要线程不销毁,就可以在线程的任何地方,调用这个参数,这是百度二面的题目,参考: Threadlocal 传递参数(百度二 ...
- 线程池-Threadlocal
ThreadLoclc初衷是线程并发时,解决变量共享问题,但是由于过度设计,比如弱引用的和哈希碰撞,导致理解难度大.使用成本高,反而成为故障高发点,容易出现内存泄露,脏数据.贡献对象更新等问题.单从T ...
随机推荐
- Linux-Shell编程之数组操作
源码 #!/bin/bash str="Array - Demo Shell"; echo ${#str} #求字符串長度 #定義 arr=('a' 'b' 'c' 'd' 'e' ...
- L1-Day9
1.学习让我感觉很棒.(什么关系?动作 or 描述?主语部分是?) [我的翻译]Learning makes me that feel good. [标准答案]Lear ...
- day06 字典、元组、set的方法及常用操作
今日内容: 1.深浅拷贝 2.元组 3.字典 4.set 1.深浅拷贝 # 1.值拷贝 # 采用赋值的方法进行 # 只会将堆区容器变量与栈区的绑定关系进行复制 # 2.浅拷贝 # 会将堆区与栈区的绑定 ...
- encode与decode
import torch from torch import nn import numpy as np import matplotlib.pyplot as plt import torch.ut ...
- 解决sqlite 删除记录后数据库文件大小不变
最的做的项目中要有到sqlite数据存储,写了测试程序进行测试,存入300万条记录,占用flash大小为 86.1M,当把表中的记录全部删除后发后数据库文件大小依然是 86.1M: 原因是:sqlit ...
- iptables系列
详情请参考:http://www.zsythink.net/archives/tag/iptables/page/2/
- NOIP2018Day1T2 货币系统
题目描述 在网友的国度中共有 \(n\) 种不同面额的货币,第 \(i\) 种货币的面额为 \(a[i]\),你可以假设每一种货币都有无穷多张.为了方便,我们把货币种数为 \(n\).面额数组为 \( ...
- 《剑指offer》翻转单词顺序列
本题来自<剑指offer> 反转链表 题目: 思路: C++ Code: Python Code: 总结:
- python json按输入顺序输出内容
通过使用collecions,进行排序.collections是一个python的内建模块. import collections dic = collections.OrderedDict() # ...
- MySQL/Oracle数据库优化总结
MySQL数据库优化的八种方式 1.选取最适用的字段属性 MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快.因此,在创建表的时候,为了获得更好的性能 ...