Java ThreadLocal类学习
ThreadLocal为线程局部变量,通过线程名(key)-对象(value)的Map来获取每个线程对应的对象。我们不能通过ThreadLocal处理多线程并发问题,但是每个线程可以通过ThreadLocal轻易的访问到自己保存的对象。
以Hibernate中sessionFactory,Session举例
在Hibernate中sessionFactory是线程安全,在web应用中只要有一份实例就行,但是Session是每个线程都各自拥有一份实例,不然不同的线程持有同一个session对象进行CRUD,会引起数据操作混乱。因此为每一个线程都分配一个独自的Session实例,这里可以应用了ThreadLocal。下面进行简单模拟,说明ThreadLocal使用
//SessioinFactory类保存一个自定义的ThreadLocalSessionContext对象
package com.localthread;
public class SessionFactory {
public ThreadLocalSessionContext sc;
public SessionFactory(){
sc= new ThreadLocalSessionContext(this);
}
public Session currentSession(){
return sc.currentSession();
}
public Session createSession(){
return new Session();
}
}
package com.localthread;
import java.util.HashMap;
import java.util.Map;
//使用ThreadLocal来保存一个以SessionFactory-Session为key-value的Map。
public class ThreadLocalSessionContext {
private SessionFactory sessionFactory;
public ThreadLocalSessionContext(SessionFactory sessionFactory){this.sessionFactory=sessionFactory;}
public SessionFactory factory(){return sessionFactory;}
private static final ThreadLocal<Map> CONTEXT_TL=new ThreadLocal();//应用ThreadLocal,其中的Map的SessionFactory(key)-Session(value)
//获得当前线程的Session,没有则用SessioinFactory创建一个
public final Session currentSession(){
Session session=exsitSession(factory());
if(session==null){
session=factory().createSession();
bind(factory(),session);
}
return session;
}
public static Map sessionMap(){
return CONTEXT_TL.get();
}
public static Session exsitSession(SessionFactory factory){
Map sessionMap=sessionMap();
if(sessionMap==null)
return null;
return (Session) sessionMap.get(factory);
}
public static void bind(SessionFactory factory,Session session){
Map sessionMap=sessionMap();
if(sessionMap==null){
sessionMap=new HashMap();
CONTEXT_TL.set(sessionMap);
}
sessionMap.put(factory, session);
}
}
package com.localthread;
//打印sessionId
public class Session {
public int sessionId=0;
public void print(){
System.out.println(Thread.currentThread().getName()+":"+this+",sessionId:"+sessionId++);
}
}
//测试类
/***
启动三个线程共享一个SessionFactory,在每个线程的Run方法中获得每个线程各自对应的Session,测试输出如下图:
其中SessionId++按照预期运行。
**/
package com.localthread;
public class Main {
public static void main(String[] args) {
SessionFactory factory=new SessionFactory();
SessionThread s1=new SessionThread(factory);
SessionThread s2=new SessionThread(factory);
SessionThread s3=new SessionThread(factory);
s1.start();s2.start();s3.start();
}
}
class SessionThread extends Thread{
private int count=5;
private SessionFactory factory;
public SessionThread(SessionFactory factory){
this.factory=factory;
}
public void run(){
while(count>0){
factory.currentSession().print();
count--;
}
}
}
执行结果:
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 2025成都.NET开发者Connect圆满结束
· 后端思维之高并发处理方案
· 千万级大表的优化技巧
· 在 VS Code 中,一键安装 MCP Server!
· 10年+ .NET Coder 心语 ── 继承的思维:从思维模式到架构设计的深度解析