TransmittableThreadLocal 解决 线程池线程复用 无法复制 InheritableThreadLocal 的问题.
ThreadLoacl,InheritableThreadLocal,原理,以及配合线程池使用的一些坑
之前为了能让InheritableThreadLocal 正确传递,不得不每次
ExecutorService executor = Executors.newFixedThreadPool(>=[任务线程数]);
或者直接new Thread. 这样不仅引起性能损耗,并且如果并发上来了,会造成不必要的上下文切换.还必须用信号量做并发控制.
偶然发现 阿里开源 TransmittableThreadLocal 可以解决此问题.
以下来实验一下
/**
* User: laizhenwei
* Date: 2018-04-12 Time: 10:07
* Description:
*/
public class Ttl { static ExecutorService executorService = Executors.newFixedThreadPool(1); public static void main(String[] args) {
//子线程每次new 所以会复制线程的InheritableThreadLocal,结果正确
// withoutThreadPool(10);
//因线程池复用线程,不会每次new 所以不会更新父线程InheritableThreadLocal 的值,导致结果错误
withThreadPool(10);
} public static void withoutThreadPool(int c){
for(int i=0;i<c;i++){
Integer var1 = (int)(Math.random()*100);
Integer var2 = (int)(Math.random()*100);
MyContextHolder.set(var1);
threadRun(var1,var2);
}
} public static void withThreadPool(int c){
for(int i=0;i<c;i++){
Integer var1 = (int)(Math.random()*100);
Integer var2 = (int)(Math.random()*100);
MyContextHolder.set(var1);
threadPoolExecute(var1,var2);
}
} public static void threadRun(Integer var1,Integer var2){
new Thread(()->assert1(var1,var2)).start();
} public static void threadPoolExecute(Integer var1,Integer var2){
executorService.execute(()->assert1(var1,var2));
} public static void assert1(Integer var1,Integer var2){
System.out.println(MyContextHolder.get()*var2==var1*var2);
} public static class MyContextHolder{ private static ThreadLocal<Integer> stringThreadLocal = new InheritableThreadLocal<>(); public static void set(Integer data) {
stringThreadLocal.set(data);
} public static Integer get() {
return stringThreadLocal.get();
}
} }
withoutThreadPool(10)输出结果

withThreadPool(10); 输出结果

解决方式
pom引入
<!-- https://mvnrepository.com/artifact/com.alibaba/transmittable-thread-local -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.2.0</version>
</dependency>
修改MyContextHolder
public static class MyContextHolder{
private static ThreadLocal<Integer> stringThreadLocal = new TransmittableThreadLocal<>();
// private static ThreadLocal<Integer> stringThreadLocal = new InheritableThreadLocal<>();
public static void set(Integer data) {
stringThreadLocal.set(data);
}
public static Integer get() {
return stringThreadLocal.get();
}
}
修改threadPoolExecute
public static void threadPoolExecute(Integer var1,Integer var2){
//使用TransmittableThreadLocal 解决
executorService.execute(TtlRunnable.get(()->assert1(var1,var2)) );
// executorService.execute(()->assert1(var1,var2));
}
运行 withThreadPool(10); 结果

TransmittableThreadLocal 解决 线程池线程复用 无法复制 InheritableThreadLocal 的问题.的更多相关文章
- android线程与线程池-----线程池(二)《android开发艺术与探索》
android 中的线程池 线程池的优点: 1 重用线程池中的线程,避免了线程的创建和销毁带来的性能开销 2 能有效的控制最大并发数,避免大量线程之间因为喜欢抢资源而导致阻塞 3 能够对线程进行简单的 ...
- C# 显式创建线程 or 使用线程池线程--new Thread() or ThreadPool.QueueUserWorkItem()
在C#多线程编程中,关于是使用自己创建的线程(Thread)还是使用线程池(ThreadPool)线程,一直很困惑,知道看了Jeffrey Richter的相关介绍才明白,记录如下: 当满足一下任何条 ...
- java 线程池线程忙碌且阻塞队列也满了时给一个拒接的详细报告
线程池线程忙碌且阻塞队列也满了时给一个拒接的详细报告.下面是一个自定义的终止策略类,继承了ThreadPoolExecutor.AbortPolicy类并覆盖了rejectedExecution方法把 ...
- 线程池线程数与(CPU密集型任务和I/O密集型任务)的关系
近期看了一些JVM和并发编程的专栏,结合自身理解,来做一个关于(线程池线程数与(CPU密集型任务和I/O密集型任务)的关系)的总结: 1.任务类型举例: 1.1: CPU密集型: 例如,一般我们系统的 ...
- EventStore .NET API Client在使用线程池线程同步写入Event导致EventStore连接中断的问题研究
最近,在使用EventStore的.NET Client API采用大量线程池线程同步写入Event时(用于模拟ASP.NET服务端大并发写入Event的情况),发现EventStore的连接会随机中 ...
- Java多线程面试题:线程锁+线程池+线程同步等
1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...
- 通过transmittable-thread-local源码理解线程池线程本地变量传递的原理
前提 最近一两个月花了很大的功夫做UCloud服务和中间件迁移到阿里云的工作,没什么空闲时间撸文.想起很早之前写过ThreadLocal的源码分析相关文章,里面提到了ThreadLocal存在一个不能 ...
- 线程池如何复用一个线程-- ThreadPoolExecutor的实现(未完)
任务是一组逻辑工作单元,而线程则是使任务异步执行的机制.在Java中,Runnable对象代表一个任务,Thread对象负责创建一个线程执行这个任务. 前提:1. 程序需要处理大量任务 2. 任务的执 ...
- 001-多线程-JUC线程池-线程池架构-Executor、ExecutorService、ThreadPoolExecutor、Executors
一.概述 1.1.线程池架构图 1. Executor 它是"执行者"接口,它是来执行任务的.准确的说,Executor提供了execute()接口来执行已提交的 Runnable ...
随机推荐
- WordPress主题开发:输出指定页面导航
实例: <ul> <li class="widget widget_nav_menu"> <?php if(is_page(array(12,14,1 ...
- Knockout.Js官网学习(Mapping高级用法二)
使用ignore忽略不需要map的属性 如果在map的时候,你想忽略一些属性,你可以使用ignore累声明需要忽略的属性名称集合: " }; var mapping = { 'ignore' ...
- How to chain a command after sudo su?
The idea is simple, for example: alias foo='sudo su foo && cd /tmp' However, it does not exe ...
- ELK菜鸟手记 (二) - 高级配置之多应用索引过滤
我们在实际的场景中,经常是多个网站或者服务端在一台服务器上,但是如果这些应用全部 记录到一台logstash服务器,大家日志都混在一起不好区分. 有人说,我可以在日志中打项目名,但是这样并不方便. 其 ...
- [Python设计模式] 第2章 商场收银软件——策略模式
github地址: https://github.com/cheesezh/python_design_patterns 题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计 ...
- Gson解析第三方提供Json数据(天气预报,新闻等)
之前都是自己写后台,自己的server提供数据给client. 近期在看第三方的数据接口,訪问其它站点提供的信息.比方.我们可能自己收集的数据相当有限.可是网上提供了非常多关于天气预报.新闻.星座运势 ...
- Jquery计算时间戳之间的差值,可返回年,月,日,小时等
/** * 计算时间戳之间的差值 * @param startTime 开始时间戳 * @param endTime 结束时间戳 * @param type 返回指定类型差值(year, month, ...
- VTK计算网格模型上的最短路径
Dijkstra algorithm to compute the graph geodesic.Takes as input a polygonal mesh and performs a sing ...
- MySQL MySql连接数与线程池
连接数 1. 查看允许的最大并发连接数 SHOW VARIABLES LIKE 'max_connections'; 2. 修改最大连接数 方法1:临时生效 SET GLOBAL max_conn ...
- Docker 管理应用程序数据
1.将Docker主机数据挂载到容器 Docker提供三种不同的方式将数据从宿主机挂载到容器中:volumes , bind mounts 和tmpfs volumes: Docker管理宿主机文件 ...