ThreadLocal

先强调一点:ThreadLocal不是用来解决共享变量问题的,它与多线程的并发问题没有任何关系。

1.基本概念?

当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

2.threadLocal是如何做到为每一个线程维护变量的副本的呢?

在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。我们自己就可以提供一个简单的实现版本。

SimpleThreadLocal 原理实现

  1. public class SimpleThreadLocal {  
  2.     private Map valueMap = Collections.synchronizedMap(new HashMap());  
  3.     public void set(Object newValue) {  
  4.                 //①键为线程对象,值为本线程的变量副本  
  5.         valueMap.put(Thread.currentThread(), newValue);  
  6.     }  
  7.     public Object get() {  
  8.         Thread currentThread = Thread.currentThread();  
  9.   
  10.                 //②返回本线程对应的变量  
  11.         Object o = valueMap.get(currentThread);   
  12.                   
  13.                 //③如果在Map中不存在,放到Map中保存起来  
  14.                if (o == null && !valueMap.containsKey(currentThread)) {  
  15.             o = initialValue();  
  16.             valueMap.put(currentThread, o);  
  17.         }  
  18.         return o;  
  19.     }  
  20.     public void remove() {  
  21.         valueMap.remove(Thread.currentThread());  
  22.     }  
  23.     public Object initialValue() {  
  24.         return null;  
  25.     }  
  26. }  

 ThreadLocal使用的例子:

  1. package com.baobaotao.basic;  
  2.   
  3. public class SequenceNumber {  
  4.        
  5.         //①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值  
  6.     private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){  
  7.         public Integer initialValue(){  
  8.             return 0;  
  9.         }  
  10.     };  
  11.        
  12.         //②获取下一个序列值  
  13.     public int getNextNum(){  
  14.         seqNum.set(seqNum.get()+1);  
  15.         return seqNum.get();  
  16.     }  
  17.       
  18.     public static void main(String[ ] args)   
  19.     {  
  20.           SequenceNumber sn = new SequenceNumber();  
  21.            
  22.          //③ 3个线程共享sn,各自产生序列号  
  23.          TestClient t1 = new TestClient(sn);    
  24.          TestClient t2 = new TestClient(sn);  
  25.          TestClient t3 = new TestClient(sn);  
  26.          t1.start();  
  27.          t2.start();  
  28.          t3.start();  
  29.     }     
  30.     private static class TestClient extends Thread  
  31.     {  
  32.         private SequenceNumber sn;  
  33.         public TestClient(SequenceNumber sn) {  
  34.             this.sn = sn;  
  35.         }  
  36.         public void run()  
  37.         {  
  38.                         //④每个线程打出3个序列值  
  39.             for (int i = 0; i < 3; i++) {  
  40.             System.out.println("thread["+Thread.currentThread().getName()+  
  41. "] sn["+sn.getNextNum()+"]");  
  42.             }  
  43.         }  
  44.     }  

执行结果:

thread[Thread-2] sn[1] 
thread[Thread-0] sn[1] 
thread[Thread-1] sn[1] 
thread[Thread-2] sn[2] 
thread[Thread-0] sn[2] 
thread[Thread-1] sn[2] 
thread[Thread-2] sn[3] 
thread[Thread-0] sn[3] 
thread[Thread-1] sn[3] 

可以看到,各个线程的longLocal值与stringLocal值是相互独立的,本线程的累加操作不会影响到其他线程的值,真正达到了线程内部隔离的效果。

3.使用场景

最常见的ThreadLocal使用场景为 用来解决数据库连接、Session管理等,那么接下来我们就看看spring事务中ThreadLocal的应用

4.总结

1、ThreadLocal能解决的问题,那肯定不是共享变量(多线程并发)问题,只是看起来有些像并发;像火车票、电影票这样的真正的共享变量的问题用ThreadLocal是解决不了的,同一时间,同一趟车的同一个座位,你敢用ThreadLocal来解决吗?

2、每个Thread维护一个ThreadLocalMap映射表,这个映射表的key是ThreadLocal实例本身,value是真正需要存储的Object

转载于:https://my.oschina.net/yangfeima/blog/1358701

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值