真实项目中 ThreadLocal 的妙用
一、什么是 ThreadLocal
ThreadLocal 提供了线程的局部变量,每个线程都可以通过 set() 和 get() 来对这个局部变量进行操作,但不会和其他线程的局部变量冲突,实现了线程间的据隔离。
简单讲:一个获取用户的请求线程 A,如果向 ThreadLocal 填充变量 AValue(只能被线程 A 操作),该变量对其他获取用户的请求线程 B、C...是隔离的.
最简单的使用方式:
类似一次 HTTP 请求线程中,利用 ThreadLocal 存储 Cookie 对象,进行状态管理。set Cookie:
private ThreadLocal httpThreadLocal = new ThreadLocal();
httpThreadLocal.set(“Cookie: sid=13420771402233”)
上面存储格式是 String ,实际场景存储的是具体的对象。在这次 HTTP 请求过程中,任何时候都可以获取 Cookie 。获取方式很简单 get Cookie:
String cookieValue = (String) httpThreadLocal.get();
Thread 与 ThreadLocal 对象引用关系图
二、你熟悉的场景
2.1 数据库连接池
比如一次请求线程进来,业务 Dao 需要更新 user 表和 user-detail 表。如果是 new 出两个数据库 Connection ,分别不同的 Connection 操作 user 表和 user-detail 表,就无法保证事务。那么数据库连接池是如何保证的?
答案是:利用 ThreadLocal 存储唯一 Connection 对象。每次请求线程,pool.getConnection 获取连接的时候都会这样操作:
- 会从 ThreadLocal 获取 Connection 对象。如果有,则保证了后面多个数据库操作共用同一个 Connection ,从而保证了事务。
- 如果没有,往 ThreadLocal 新增Connection 对象,并返回到线程
错误的做法
public class XXXService {
private Connection conn;
}
因为 conn 是线程不安全的。这样会导致多个请求公用一个连接。请求量很大的情况下,延迟各种。你懂。
因此,使用 ThreadLocal 保证每个请求线程的 Connection 是唯一的。即每个线程有自己的连接。
继续讲到 Spring 框架,在事务开始时,会给当前线程一个Jdbc Connection,在整个事务过程,都是使用该线程绑定的connection来执行数据库操作,实现了事务的隔离性。Spring框架里面就是用的ThreadLocal来实现这种隔离
2.2 HTTP Cookie
比如你访问百度、我访问百度,会有不同 Cookie 。而且你不能访问我的 Cookie,我也不能。顾名思义,使用 ThreadLocal 保证每个 HTTP 请求线程的 Cookie 是唯一的。
Cookie 这样才能做 Session 等状态管理。
三、实战场景
总结一下就是:ThreadLocal 可以让同一个线程中上下文之间数据共享
在上面章节 二、你熟悉的场景 其实介绍了很多现有场景。那么我这边具体的实战场景是什么?
简单的例子:
适用满足这两个条件的场景:1.每个线程独有的一些信息,2.这些信息又会在多个方法或类中用到。
- 一个请求线程,里面有两个异步小线程,各有一个方法。分别处理 A 或 B 业务
- 一种方法是传递不可变的入参
- 另一种就是 ThreadLocal,放在 ThreadLocal 的入参,会被各个方法共享。而且多个请求线程互不影响
复杂的例子:
一次发货操作:会根据入参,进行组件化、流程编排话。那么入参会被各个地方用到,而且有些流程组件是异步的(类似 new thread 操作的)。这时候可以定一个 XXContext 上下文:
public class XXContext {
private static ThreadLocal<Map<Class<?>, Object>> context = new InheritableThreadLocal<>();
/**
* 把参数设置到上下文的Map中
*/
public static void put(Object obj) {
Map<Class<?>, Object> map = context.get();
if (map == null) {
map = new HashMap<>();
context.set(map);
}
if (obj instanceof Enum) {
map.put(obj.getClass().getSuperclass(), obj);
} else {
map.put(obj.getClass(), obj);
}
}
/**
* 从上下文中,根据类名取出参数
*/
@SuppressWarnings("unchecked")
public static <T> T get(Class<T> c) {
Map<Class<?>, Object> map = context.get();
if (map == null) {
return null;
}
return (T) map.get(c);
}
/**
* 清空ThreadLocal的数据
*/
public static void clean() {
context.remove();
}
}
代码解析:
- 都是 static 操作,类似 DateUtil 玩法
- 记得每次请求线程后清理。可以 AOP 去清理,加个注解就行。因为同一个请求线程可能被业务方公用。
(完)

真实项目中 ThreadLocal 的妙用的更多相关文章
- Java算法之递归打破及在真实项目中的使用实例
开心一笑 刚才领导问开发:"你觉得这个项目的最大风险是什么",开发说:"加班猝死" , 气氛尴尬了一分钟!!! 提出问题 1.递归算法简单复习 2.如何实现递归 ...
- memcached真实项目中的应用
上一篇memcached介绍及基本使用介绍了memcached的一些基本概念和一个范例.这一篇将介绍一个memcached在实际项目中的应用
- 【一起学设计模式】观察者模式实战:真实项目中屡试不爽的瓜娃EventBus到底如何实现观察者模式的?
申明 本文章首发自本人公众号:壹枝花算不算浪漫,如若转载请标明来源! 感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫 22.jpg 前言 之前出过一个设计模式的系列文章,这些文章和其他讲设计模式的文 ...
- 真实项目中VS2015中自建T4模板生成文件的使用
有可能许多小伙伴们发现,vs2015和2012的自带T4模板中的.tt文件改变非常之多,如果仅仅copyEF系统自己生成的模板文件,那可累了.以下是我自己整理的在2012和2015中都可以试用的代码. ...
- java使用elasticsearch进行模糊查询-已在项目中实际应用
java使用elasticsearch进行模糊查询 使用环境上篇文章本人已书写过,需要maven坐标,ES连接工具类的请看上一篇文章,以下是内容是笔者在真实项目中运用总结而产生,并写的是主要方法和思路 ...
- Web项目中得到访问者的真实ip
Web项目中得到访问者的真实ip 描述:最近要实现个功能是要记录管理员登录的真实ip,但在项目中如果直接使用request.getRemoteAddr()获得ip的话,获得的可能不是真实ip,是因为使 ...
- 编写Java程序,使用ThreadLocal类,项目中创建账户类 Account,类中包括账户名称name、 ThreadLocal 类的引用变量amount,表示存款
查看本章节 查看作业目录 需求说明: 某用户共有两张银行卡,账户名称相同,但卡号和余额不同.模拟用户使用这两张银行卡进行消费的过程,并打印出消费明细 实现思路: 项目中创建账户类 Account,类中 ...
- JAVA WEB项目中各种路径的获取
JAVA WEB项目中各种路径的获取 标签: java webpath文件路径 2014-02-14 15:04 1746人阅读 评论(0) 收藏 举报 分类: JAVA开发(41) 1.可以在s ...
- 转:C++项目中的extern "C" {}
引言 在用C++的项目源码中,经常会不可避免的会看到下面的代码: #ifdef __cplusplus extern "C" { #endif /*...*/ #ifdef __c ...
随机推荐
- Robot Framework安装指南
安装软件下载列表: 2012年5月15日更新 1.python 2.7http://www.python.org/download/http://www.python.org/ftp/python/2 ...
- hdu 4374 单调队列
求一个最大k连续的子序列和 单调队列 #include<stdio.h> #include<string.h> #include<iostream> using ...
- 国内大型的内部 C# 编程规范
C#编程规范 改动记录 Ver. No 发版日期 编制人 批准人 改动的说明 目 录 1 1.1 1.2 2 2.1 2.1.1 Pascal 大写和小写 2.1.2 Came ...
- 微信公众号开发系列-Http请求包基类
HttpHelper请求包基类,支持get请求和POS要求.以促进微通道交互界面的开发,为了准备的人机交互界面,背部. 1.HttpHelper帮助基类 [csharp] view plaincopy ...
- Dijkstra含权图最短路径;审判,不要错过枚举退款保证不会重复;国际象棋八皇后问题
求两节点的最短通路.对于无权图,能够通过图的广度优先遍历求解.含权图一般通过Dijkstra算法求解. import java.util.ArrayList; import java.util.Has ...
- html5 命运之轮生产
码,如以下: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEn ...
- 2018-4-25-- 2.在sublime3里安装git插件并连接GitHub
1.配置全局参数 Git的主要配置包括用户名.邮箱的设置.以及生成SSH密钥公钥等. 首先运行一下的命令设置git提交代码时自己的用户信息. 2.在sublime3里使用时需要配置push.defau ...
- MySql5.7.11 for Windows 安装精简版(一)
原文:MySql5.7.11 for Windows 安装精简版(一) 从官网下载压缩包,我下载的是64位的.解压. 精简: -Bin下只保留 mysqladmin.exe mysqld.exe my ...
- Tensorflow中循环神经网络及其Wrappers
tf.nn.rnn_cell.LSTMCell 又名:tf.nn.rnn_cell.BasicLSTMCell.tf.contrib.rnn.LSTMCell 参见: tf.nn.rnn_cell.L ...
- Openssl - Static libraries (w32, mingw) 以及对Qt静态编译时的设置
Openssl static libraries created for Windows 32bit using MinGW compiler Compiled with: ./Con ...