ThreadLocal
来源:互联网 发布:自动刷火车票软件 编辑:程序博客网 时间:2024/06/08 06:34
1.ThreadLocal源码解读
(1)get()
get()方法是用来获取ThreadLocal在当期线程中保存的变量副本。
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方法中的操作
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }可以看出,实际上是从当前线程t中获得成员变量threadLocals。那么再看一下Thread类中的threadLocals成员变量
ThreadLocal.ThreadLocalMap threadLocals = null;发现其实也就是一个ThreadLocal类中定义的一个内部类ThreadLocalMap类的对象,继续看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; } }....... }那么就可以看出,实际上ThreadLocalMap也是一个Map,将ThreadLocal作为key
继续看get()中的setInitialValue()方法
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; }可以看出如果map不为空,则直接将this作为key存储到ThreadLocalMap中,否则则创建Map,creteMap方法为:
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }也就是说如果map为空,则直接创建一个即可
(2)set(T value)
set(T value)方法是用来设置当期线程中变量的副本。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }可以看出,也就是在当前线程的Thread对象中的ThreadLocalMap中设置对应的值
2.ThreadLocal应用
看一个例子
public class ThreadLocalTest {public static void main(String[] args) throws InterruptedException {final Local local = new Local();local.set(1,"main");new Thread(new Runnable() {@Overridepublic void run() {local.set(2,"sub");local.show();}}).start();Thread.sleep(1000);local.show();}}class Local{private ThreadLocal<Long> longLocal = new ThreadLocal<Long>();private ThreadLocal<String> strLocal = new ThreadLocal<String>();public void set(long l,String n){longLocal.set(l);strLocal.set(n);}public void show(){System.out.println(longLocal.get());System.out.println(strLocal.get());}}结果为:
2sub1main
可以看出,每个线程都有自己的值,说明ThreadLocal起作用了
3.ThreadLocal理解
由于是在Thread类中定义一个Map,所以必然就能不同线程不同值
4.ThreadLocal应用场景
假设有一个数据库连接类,维护了一个数据库连接:
class ConnectionManager { private static Connection connect = null; public static Connection openConnection() { if(connect == null) { connect = DriverManager.getConnection(); } return connect; } public static void closeConnection() { if(connect!=null) connect.close(); }}在单线程程序中,这段代码没有任何问题,但是放在多线程情况下,会存在以下两个问题:1.两个方法都没有进行同步,可能会在openConnection中多次创建connect 2.由于connect是共享变量,所以所有线程都是用这一个变量,那么一个线程在是用的时候,其他线程很有可能在closeConnextion关闭连接,从而导致问题
所以处于安全考虑,必须将这两个方法进行同步处理。
但是由于所有线程共享一个connect,所以当一个线程在进行同步操作的时候,其他线程只能等待,这样会使效率非常低
实际上,数据库连接完全可以不用共享,那么直接改为在方法中调用如何呢?
class ConnectionManager { private Connection connect = null; public Connection openConnection() { if(connect == null){ connect = DriverManager.getConnection(); } return connect; } public void closeConnection() { if(connect!=null) connect.close(); }} class Dao{ public void insert() { ConnectionManager connectionManager = new ConnectionManager(); Connection connection = connectionManager.openConnection(); //使用connection进行操作 connectionManager.closeConnection(); }}这样做确实没有问题,但是由于每次都是在方法内部创建连接,那么就会导致服务器压力非常大,严重影响程序性能。
这种情况最适合使用ThreadLocal,因为ThreadLocal会对每一个线程内部构造一个副本,并且在线程内部任何地方都可以使用,这样一来就不存在线程安全问题,也不会严重影响程序性能。
ThreadLocal最适合这种每个线程都需要保存自己副本的情况,比如数据库连接池,Session等
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {public Connection initialValue() { return DriverManager.getConnection(DB_URL);}}; public static Connection getConnection() {return connectionHolder.get();}重写了initialValue方法,也就是在线程初始化的时候创建一个数据库连接
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;}用来管理Session
0 0
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- threadlocal
- ThreadLocal
- ThreadLocal
- 【02】Android四大基本组件
- UML建模
- Nat回环(Lan——>Lan端口映射原理)
- 使用shape为android各种元素制作圆角
- MongoDB 聚合管道(二)(Aggregation Pipeline)
- ThreadLocal
- 常去网站
- 手动配置springMVC4的方法
- Java生成中文汉字随机验证码
- 关于大型网站技术演进的思考(二)--存储的瓶颈(2)
- 32位和64位系统区别及int字节数
- 权限管理——RBAC模型总结
- Excel报表支持的56种颜色(Excel2003及以下版本)
- 为arm和51单片机安装keil(MDK)软件