该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-04-17
经典,那可以这样理解了,threadLocal是为一的,里面保存个Map
map里面的key和Thread相关,每一个Thread key唯一。 |
|
返回顶楼 | |
发表时间:2007-04-17
jamesby 写道 经典,那可以这样理解了,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是共享的,看看是什么结果。有助于加深理解。 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"; } 搂主在第十楼写的程序写错了,第22行该改成 new Thread(new TestThread(testThreadLocal)).start(); 你会观察到很有趣的现象。想明白了,这个ThreadLocal就搞明白了。 由于ThreadLocal的编程接口有set, get,很容易让人误会数据是存在这个ThreadLocal对象里面的,实际不是的,数据是存在Thread里面的,ThreadLocal只是提供了操作。 如果Thread的接口改成这样: Thred.currentThread().getThreadLocalStorage().get(key); Thred.currentThread().getThreadLocalStorage().put(key, myValue); 就不会引起这么多误会。不过ThreadLocal是Java 1.2才加的,可能是因为不想改变原有Thread的接口。 |
|
返回顶楼 | |
发表时间:2007-04-18
多谢bigpanda的进一步讲解!范例程序暂时还没有看,但是大意已经理解了,就是每个 Thread 都保存一个自己的 Map,key 就是 ThreadLocal 变量,而 value 就是在对应 Thread 运行语句 threadLocal.set(object) 时放进去的那个 object !!所以,即使 ThreadLocal 变量是同一个,但因为在不同的 Thread 里面访问的是不同的 Map,所以 threadLocal.get() 总返回不同的object!!
我现在基本上完全明白了。谢谢bigpanda的时间! 再补充一个小问题,那照这样说,是不是“ThreadLocal 里面有 Map,而当前 Thread 就是key”的说法错误了? |
|
返回顶楼 | |
发表时间:2007-04-18
非典型程序员 写道 再补充一个小问题,那照这样说,是不是“ThreadLocal 里面有 Map,而当前 Thread 就是key”的说法错误了?
错了,给搞反了。 另外你去看看十楼你写的多线程程序,第22行写错了。 |
|
返回顶楼 | |
发表时间:2007-04-18
bigpanda 写道 非典型程序员 写道 再补充一个小问题,那照这样说,是不是“ThreadLocal 里面有 Map,而当前 Thread 就是key”的说法错误了?
错了,给搞反了。 另外你去看看十楼你写的多线程程序,第22行写错了。 发现了发现了,把 start() 写成 run() 了~~ |
|
返回顶楼 | |
发表时间:2007-04-19
好了,测试代码最后修正版本~~
public class ThreadLocalTest { private static final ThreadLocal session = new ThreadLocal(); private static class TestThread implements Runnable { private ThreadLocal sessionInThread; public TestThread(ThreadLocal session) { sessionInThread = session; } public void run() { sessionInThread.set(new Object()); showInfo(); showInfo(); // Show again, for verification. } private void showInfo() { try { Thread.sleep(300); } catch (InterruptedException ie) { return; } System.out.println(Thread.currentThread().getName() + ":ThreadLocal object passed in:" + sessionInThread + ",ThreadLocal object content: " + sessionInThread.get()); } } public static void main(String[] args) { for (int i = 0; i < 6; i ++) { new Thread(new TestThread(session), "thread_" + i).start(); } } } |
|
返回顶楼 | |
发表时间:2007-05-25
public class ThreadLocalTest { private static class TestThread implements Runnable { private static final ThreadLocal session = new ThreadLocal(); private ThreadLocal sessionInThread; public TestThread() { sessionInThread = session; } public void run() { sessionInThread.set(new Object()); showInfo(); showInfo(); // Show again, for verification. } private void showInfo() { try { Thread.sleep(300); } catch (InterruptedException ie) { return; } System.out.println(Thread.currentThread().getName() + " :ThreadLocal object passed in:" + sessionInThread + ", ThreadLocal object content: " + sessionInThread.get()); } } public static void main(String[] args) { for (int i = 0; i < 6; i ++) { new Thread(new TestThread(), "thread_" + i).start(); } } } 这样是不更能表达楼主的意思 |
|
返回顶楼 | |