为了账号安全,请及时绑定邮箱和手机立即绑定

关于线程池的线程复用问题

关于线程池的线程复用问题

泛舟湖上清波郎朗 2019-02-18 20:28:20
在这篇博客中https://www.cnblogs.com/sweet...看到以下观点 package thread.base.threadloacl; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * * @author ZhenWeiLai * */ public class B { static final InheritableThreadLocal<String> threadParam = new InheritableThreadLocal<>(); public static void main(String[] args) throws InterruptedException { //固定池内只有存活3个线程 ExecutorService execService = Executors.newFixedThreadPool(3); //死循环几次才能看出效果 while (true) { //线程1,里面有两个子线程 Thread t = new Thread(()->{ threadParam.set("abc"); System.out.println("t1:" + threadParam.get()); Thread t2 = new Thread(()->{ System.out.println("t2:" + threadParam.get()); // threadParam.remove(); }); execService.execute(t2); Thread t3 = new Thread(()->{ System.out.println("t3:" + threadParam.get()); // threadParam.remove(); }); execService.execute(t3); }); execService.execute(t); TimeUnit.SECONDS.sleep(1); //线程4,线程1同级 Thread t4 = new Thread(()-> { threadParam.set("CBA"); System.out.println("t4:" + threadParam.get()); }); execService.execute(t4); } } } t1:abc t2:abc t3:abc t4:CBA t1:abc t2:abc t3:abc t4:CBA t1:abc t2:abc t3:CBA //因复用线程而导致问题 t4:CBA 我想请问,线程复用导致t3输出CBA是怎么样的一个过程?Ps:在jdk8下已经复现此问题。 2018年1月18日15:04:32 问题补充:我使用UnSafe的staticFieldOffset获取对象的内存地址,四个线程内部分别执行,地址是一致的。或许是staticFieldOffset这个方法并不是获取内存地址的? try { Field threadParamF = ThreadPool_1.class.getDeclaredField("threadParam"); System.out.println("t1 threadParam location:" + unsafe.staticFieldOffset(threadParamF)); } catch (NoSuchFieldException e) { e.printStackTrace(); }
查看完整描述

6 回答

?
慕容森

TA贡献1853条经验 获得超18个赞

ExecutorService execService = Executors.newFixedThreadPool(3);

这句的意思是有三个线程在同时运行。
t3打印之前那一刻,t4恰好改变了threadParam.set("CBA");,然后,t3打印出来就是t3:CBA

查看完整回答
反对 回复 2019-03-01
?
开心每一天1111

TA贡献1836条经验 获得超13个赞

ThreadLocal基本上可以理解为以当前Thread为键的Map,执行过t4的Thread再执行t3就会出现这种情况

查看完整回答
反对 回复 2019-03-01
?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

ThreadLocal在线程结束时没有清空,导致在下一次线程运行时读到旧值。

查看完整回答
反对 回复 2019-03-01
?
月关宝盒

TA贡献1772条经验 获得超5个赞

就是线程的复用,才是t3的线程正好是上次t4的线程,所以取出的threadlocal是同一个。想知道就把每次线程名字或者id输出看看。我本地已经测试,所有非t4的CBA的线程的上一次输出一定是CBA,就是线程复用问题。

查看完整回答
反对 回复 2019-03-01
?
幕布斯7119047

TA贡献1794条经验 获得超8个赞

你new的t1 2 3 4不是当做线程使用的,只是执行了他们的run(),真正在运行的是executeService的3个线程,ThreadLocal对象是这3个线程持有的,跟你new的4个没关系

查看完整回答
反对 回复 2019-03-01
?
慕斯王

TA贡献1864条经验 获得超2个赞

threadlocal 关联的是当前执行线程,jdk中threadlocal的实现只跟线程ID相关,跟线程执行体无关。你的线程池采用的是Executors.newFixedThreadPool(3),意味着你定义的4个线程体的执行会有复用情况,这个时候就会出现你现在所产生的现象。

查看完整回答
反对 回复 2019-03-01
  • 6 回答
  • 0 关注
  • 494 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信