java的ThreadLocal简介和示例
来源:互联网 发布:三星s8续航优化教程 编辑:程序博客网 时间:2024/05/02 00:25
Java中的ThreadLocal这个类的名字乍看容易让人误解,其实应该叫做ThreadLocalVaraiableKey,这个类的实例是作为key将对应的value存储在当前线程,value才是真正有用的信息。请注意,ThreadLocal对象仅仅是作为线程共享变量map里面的key来使用,其本身并不存储相关信息。一些安全框架如apache shiro和spring security等,都会将登录用户的信息保存到当前线程中,以便在后续的调用中可以调用静态方法获取到,而不是将用户信息作为参数传递到每个被调用的方法中。
下面看一下具体的实现方式和一个例子。
首先java.lang.Thread
有ThreadLocal.ThreadLocalMap
类型的一个成员用以存储当前线程所有的ThreadLocal
变量
public class Thread implements Runnable { ... ... /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; ... ... }
以apache shiro为例,
SecurityUtils.getSubject().getPrincipal()
能获取当前线程的principal(其实往往就是login user),注意SecurityUtils.getSubject()是静态方法。下面看一下具体的调用栈ThreadContext的resources是一个ThreadLocal的变量,其本身就是一个map。getSubject最终就是获取resources这个map里面字符串常量
SUBJECT_KEY
对应的value。可以看到resources是final的,其hash code不会更改,因此可以作为map的key使用。下面看一下ThreadLocal的实现,如何将ThreadLocal对象作为key通过get方法获取到对应value。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); // 获取Thread中所有的ThreadLocal变量的map if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this);//以调用get方法的对象this为参数,获取map中对应的value if (e != null) return (T)e.value; } return setInitialValue();}
map.getEntry(this);
就是以ThreadLocal对象为key获取对应的value。
下面的示例代码是从网上看到的,虽然有点绕,但能够帮助理解ThreadLocal。刚开始看以为输出是乱序的1-9这九个数字。
public class SequenceNumber{ // ①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值 private final static ThreadLocal<Integer> seqNumVar = new ThreadLocal<Integer>() { public Integer initialValue() { return 0; } }; // ②获取下一个序列值 public int getNextNum() { seqNumVar.set(seqNumVar.get() + 1); return seqNumVar.get(); } public static void main(String[] args) { SequenceNumber sn = new SequenceNumber(); // ③ 3个线程共享sn,各自产生序列号 TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); } private static class TestClient extends Thread { private SequenceNumber sn; public TestClient(SequenceNumber sn) { this.sn = sn; } public void run() { for (int i = 0; i < 3; i++) {// ④每个线程打出3个序列值 System.out.println("thread[" + Thread.currentThread().getName() + "] sn[" + sn.getNextNum() + "]"); } } }}
各个线程的输出次序不考虑的话,输出结果可能是
thread[Thread-2] sn[1]
thread[Thread-0] sn[1]
thread[Thread-1] sn[1]
thread[Thread-1] sn[2]
thread[Thread-1] sn[3]
thread[Thread-2] sn[2]
thread[Thread-2] sn[3]
thread[Thread-0] sn[2]
thread[Thread-0] sn[3]
也就是3个线程的序列分别从1开始,seqNumVar
作为三个线程共用的ThreadLocal,序列值互不影响。原因可以简单描述如下:每个线程输出时,都调用ThreadLocal变量seqNumVar
的get方法,这时当前线程的ThreadLocal变量map中并没有seqNumVar
作key的value,因此在map中添加seqNumVar
-0这组key-value,并返回初始值0。
- java的ThreadLocal简介和示例
- Java中的ThreadLocal示例.
- java-ThreadLocal简介
- Java 多线程之--ThreadLocal 简介
- MongoDB 和 MongoMapper的示例用法简介
- java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例
- java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例
- java的ThreadLocal类
- java的ThreadLocal
- java ThreadLocal的使用
- 学习java的ThreadLocal
- JAVA的ThreadLocal
- Java ThreadLocal的使用
- 【Java ThreadLocal的使用】
- Java ThreadLocal的使用
- JAVA Threadlocal 的使用
- Java ThreadLocal的使用
- java的ThreadLocal
- org.hibernate.QueryException: could not resolve property 错误解析
- HDU 2055 An easy problem
- mysql 用命令操作mysql是报错ERROR 1044 (42000): Access denied for user ''@'localhost' to database 'wang'
- O(1)空间内实现矩阵转置
- 星际穿越
- java的ThreadLocal简介和示例
- VM下安装Centos 出现的错误 RAM not enough
- 线程同步辅助类
- 一些滤波操作1403:图像处理基础部分
- 荷兰国旗
- 【cocos2dx】对cocos2d 之autorelease\ratain\release的理解
- 2.1 Java程序的构成
- UVa 10129 - Play on Words(DFS判连通+欧拉回路)
- Android 3D 实验总结