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 ...
随机推荐
- 原生JS实现简易评论更新功能
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- JavaScript在div后添加删除div
var idd = 'str'; $('.task-done-detail-content-p7').click(function () { var id = this.id; if(idd !== ...
- 移动端-处理后台传过来的html中图片的显示
function DealWithImg() { var width = 0; if (window.screen.width) { width = window.screen.width; } el ...
- Appnium-API-Session
Session Create New Session Java: DesiredCapabilities desiredCapabilities = new DesiredCapabilities() ...
- CV code references
转:http://www.sigvc.org/bbs/thread-72-1-1.html 一.特征提取Feature Extraction: SIFT [1] [Demo program][SI ...
- 012_TCP keepalive 和 http keep-alive
TCP keepalive概念在使用TCP长连接(复用已建立TCP连接)的场景下,需要对TCP连接进行保活,避免被网关干掉连接.在应用层,可以通过定时发送心跳包的方式实现.而Linux已提供的TCP ...
- web文件下载
web页面实现文件下载的几种方法 今天碰到文件下载的一些问题,本着知其然也要知其所以然的精神,站在巨人的肩膀上深入学习和测试了一下,抛砖引玉,现在总结结论如下: 1)标准URL下载方式可以通过在web ...
- jsp多模块相同数据提交到后台之数据处理
最近在写一个java多模块表单提交,起初想的只是一个简单的form表单提交,写的时候发现不是真简单.多个相同类型数据提交到后台接收的问题很困难. 于是,和人进行深入的讨论,感觉j以json的格式提交时 ...
- 《剑指offer》翻转单词顺序列
本题来自<剑指offer> 反转链表 题目: 思路: C++ Code: Python Code: 总结:
- 使用 Appium 测试微信小程序 Webview
打开调试功能 通过微信打开debugx5.qq.com,或者直接扫下面二维码 勾选[打开TBS内核Inspector调试功能] Chrome查看页面元素 手机连接电脑,查看是否连接成功.如下展 ...