`
ytuwlg
  • 浏览: 91288 次
  • 性别: Icon_minigender_1
  • 来自: 威海
社区版块
存档分类
最新评论

ThreadLocal

    博客分类:
  • java
阅读更多
  1. threadLocal是线程隔离的。

  2. threadLocal是为了解决单线程内跨类跨方法调用的。

  3. threadLocal可以用于隐式参数传递。

  4. 在web应用中,一般的web container都有线程池的概念。每一个request都会从线程池中获得一个线程,处理完后线程返回线程池。web container 保证同一时间处理各个请求的线程是唯一的,但不保证每次请求线程都是唯一的。因此,一般在web应用中,一般采用filter将变量保存到ThreadLocal中,处理结束后清除变量。



     注:线程池的概念。
引用
ThreadLocal实际上是一个类似HashMap的东西,这个HashMap的key就是Thread.currentThread(),而value就是你放进去的东西。所以说每次当你从ThreadLocal Variable中取对象的时候,你是默认拿自己当前的currentThread做为key去查找对应的value对象的。因此不管被运行的代码跨越了多少class,只要在1次运行的thread中的代码取到的都是同一个对象。

public class HibernateSession {   
  
  private static final ThreadLocal currentThread = new ThreadLocal();;   
  
  public static synchronized Session openSession(); throws HibernateException {   
    Session s = (Session); currentThread.get();;   
    if (s == null); {   
      s = HibernateSessionFactory.getSessionFactory();.openSession();;   
      currentThread.set(s);;   
    }   
    return s;   
  }   
  
  public static void closeSession(); throws HibernateException {   
    Session s = (Session); currentThread.get();;   
    currentThread.set(null);;   
    if (s != null); s.close();;   
  }   
}  

引用

引用
经典,那可以这样理解了,threadLocal是为一的,里面保存个Map
map里面的key和Thread相关,每一个Thread key唯一。




这种理解是不正确的。

Thread里面保存了个Map,threadLocal是个map entry key。ThreadLocal的实现决定了这ThreadLocal类的所有的对象,它们的key都不一样,所以可以用来做map entry key。

而同一个ThreadLocal的对象,是可以放在不同的thread的map里面的. 我不熟悉Hibernate,不过看楼主的例子,就是这样的, 这个key可以同时出现在不同的thread的map里面。

这个key所对应的map entry value,是要自己定义的,每次呼叫threadLocalObj.set(myValue),就把thread的里面的map里面的threadLocalObj这个key对应的value更新了。

下面给个捣乱的程序,map entry value是共享的,看看是什么结果。有助于加深理解。

Java代码
 
public class TestThreadLocal {   
  public static ThreadLocal<Mutable> t1 = new ThreadLocal<Mutable>();   
  public static ThreadLocal<Mutable> t2 = new ThreadLocal<Mutable>();   
  public static ThreadLocal<Mutable> t3 = new ThreadLocal<Mutable>();   
  public static Mutable m = new Mutable();   
       
  public static void main(String[] args) {   
    TestThread tt1 = new TestThread(t1, 5, 3, "tt1");   
    TestThread tt2 = new TestThread(t2, 7, 5, "tt2");   
    t3.set(m);   
    System.out.println("Main thread: -> " + m.str);   
  
    tt1.start();   
    tt2.start();   
           
    while(tt1.isAlive() || tt2.isAlive()) {   
      Mutable mutable = t3.get();   
      try {   
        Thread.sleep(2000);   
      } catch(Exception ex) { }   
      System.out.println("Main thread: -> " + mutable.str);   
      System.out.println(m==mutable);   
    }   
    System.out.println("Final, main thread: -> " + m.str);          
  }   
}   
  
class TestThread extends Thread {      
  private ThreadLocal<Mutable> threadLocal;      
  private int count;   
  private int sleep;   
  private String id;   
     
  public TestThread(ThreadLocal<Mutable> threadLocal, int count, int sleep,    
                    String id) {      
    this.threadLocal = threadLocal;            
    this.count = count;   
    this.sleep = sleep;   
    this.id = id;   
  }      
     
  public void run() {   
    this.threadLocal.set(TestThreadLocal.m);   
       
    for(int i=1; i<=count; i++) {   
      threadLocal.get().str = "Thread " + id +    
         " changes mutable, iteration " + i;   
      System.out.println(threadLocal.get().str);   
      try {   
        Thread.sleep(sleep*1000);   
      } catch (Exception ex) {};   
    }      
  }   
}   
  
class Mutable {   
  public String str = "mutable";   
}  



你会观察到很有趣的现象。想明白了,这个ThreadLocal就搞明白了。

由于ThreadLocal的编程接口有set, get,很容易让人误会数据是存在这个ThreadLocal对象里面的,实际不是的,数据是存在Thread里面的,ThreadLocal只是提供了操作。

如果Thread的接口改成这样:

Java代码
Thred.currentThread().getThreadLocalStorage().get(key);   
Thred.currentThread().getThreadLocalStorage().put(key, myValue); 



就不会引起这么多误会。不过ThreadLocal是Java 1.2才加的,可能是因为不想改变原有Thread的接口。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics