java并发-ThreadLocal
2016-04-20 20:18
465 查看
##基本概念
ThreadLocal提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
##实例
运行结果:
使用ThreadLocal处理数据库连接:(代码来自网络)
Hibernate中处理session
protected T initialValue() 返回此线程局部变量的当前线程的“初始值”。
void remove() 移除此线程局部变量当前线程的值。
void set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值。
ThreadLocal中是有一个Map,
get()
第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到
setInitialValue()方法我们可以看出,map不为空,就设置键值对,为空,再创建Map
我们可以看出创建map是线程中调用ThreadLocalMap。
移除此线程局部变量当前线程的值。如果此线程局部变量随后被当前线程读取,且这期间当前线程没有设置其值,则将调用其 initialValue() 方法重新初始化其值。这将导致在当前线程多次调用 initialValue 方法。
ThreadLocal提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
##实例
public class ThreadLocalExample { public static class MyRunnable implements Runnable { private ThreadLocal<String> threadLocal = new ThreadLocal<>(); @Override public void run() { threadLocal.set(Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { } System.out.println(threadLocal.get()); } } public static void main(String[] args) { MyRunnable sharedRunnableInstance = new MyRunnable(); Thread thread1 = new Thread(sharedRunnableInstance); Thread thread2 = new Thread(sharedRunnableInstance); thread1.start(); thread2.start(); } }
运行结果:
Thread-0 Thread-1
使用ThreadLocal处理数据库连接:(代码来自网络)
public class ConnectionManager { /** 线程内共享Connection,ThreadLocal通常是全局的,支持泛型 */ private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>(); public static Connection getCurrConnection() { // 获取当前线程内共享的Connection Connection conn = threadLocal.get(); try { // 判断连接是否可用 if(conn == null || conn.isClosed()) { // 创建新的Connection赋值给conn(略) // 保存Connection threadLocal.set(conn); } } catch (SQLException e) { // 异常处理 } return conn; } /** * 关闭当前数据库连接 */ public static void close() { // 获取当前线程内共享的Connection Connection conn = threadLocal.get(); try { // 判断是否已经关闭 if(conn != null && !conn.isClosed()) { // 关闭资源 conn.close(); // 移除Connection threadLocal.remove(); conn = null; } } catch (SQLException e) { // 异常处理 } } }
Hibernate中处理session
private static final ThreadLocal threadSession = new ThreadLocal(); public static Session getSession() throws InfrastructureException { Session s = (Session) threadSession.get(); try { if (s == null) { s = getSessionFactory().openSession(); threadSession.set(s); } } catch (HibernateException ex) { throw new InfrastructureException(ex); } return s; }
源码分析
1:ThreadLocal中的方法T get()返回此线程局部变量的当前线程副本中的值。
protected T initialValue() 返回此线程局部变量的当前线程的“初始值”。
void remove() 移除此线程局部变量当前线程的值。
void set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值。
public void set(T value) { // 获取当前线程对象 Thread t = Thread.currentThread(); // 获取当前线程本地变量Map ThreadLocalMap map = getMap(t); // map不为空 if (map != null) // 存值 map.set(this, value); else // 创建一个当前线程本地变量Map createMap(t, value); } /** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) { // 获取当前线程的本地变量Map return t.threadLocals; }
ThreadLocal中是有一个Map,
ThreadLocalMap,ThreadLocalMap是ThreadLocal的一个内部类。当使用ThreadLocal存值时,首先是获取到当前线程对象,然后获取到当前线程本地变量Map,最后将当前使用的ThreadLocal和传入的值放到Map中,这样做的好处是,每个线程都对应一个本地变量的Map,所以一个线程可以存在多个线程本地变量。
get()
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } // 如果值为空,则返回初始值 return setInitialValue(); }
第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
setInitialValue()方法我们可以看出,map不为空,就设置键值对,为空,再创建Map
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
我们可以看出创建map是线程中调用ThreadLocalMap。
static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
移除此线程局部变量当前线程的值。如果此线程局部变量随后被当前线程读取,且这期间当前线程没有设置其值,则将调用其 initialValue() 方法重新初始化其值。这将导致在当前线程多次调用 initialValue 方法。
相关文章推荐
- java--Servlet操作注意事项
- 在MyEclipse中上传项目到github的步骤(很详细)
- java设计模式之简单工厂模式
- Java 字节流与字符流的区别
- 单例模式的创建(Java版)
- 获取java方法签名
- Java反射实现接口
- Java NIO写事件处理技巧
- Spring框架AOP的配置和实现的简单例子
- struts2中的Action接收表单传递过来的参数
- java synchronized详解
- android studio 项目引用eclipse 依赖时的问题
- LeetCode341 Flatten Nested List Iterator(迭代器模式实践) Java
- Java之LinkedList源码解读(JDK 1.8)
- java序列化(Serializable)的作用和反序列化
- 关于Java静态代码块、初始化块、构造函数的调用顺寻问题?
- java IO 流
- Java - 验证邮箱地址是否符合要求
- Java:如何正确使用Timer
- java毕向东听课笔记19(字符串3)