论坛首页 入门技术论坛

JVM 唯一,还是每个thread一个?有关 ThreadLocal 生成实例数量的困惑。

浏览 13045 次
该帖已经被评为新手帖
作者 正文
   发表时间:2007-04-16  
public class SampleClass  
{  
    public static final ThreadLocal session = new ThreadLocal();  
    ...
}


以上这段代码,一个普通的类,里面一个static成员,成员类型为“ThreadLocal”,并且是final的。

通常我们很熟悉,类里面“static final”的东东都是JVM 唯一的,可以用来放一些常量。

但是,现在,按照“ThreadLocal”的定义,每一个执行到此语句的thread都会得到自己的一个“session”实例。这也是我们用来解决 Hibernate open session in view 的办法。

那么,请教了,在这种既“static”,又“ThreadLocal”的情况下,整个 JVM 里面的“session”实例,到底是单个还是多个呢?

如果是多个,是否可以说,Java类的“static”成员将不一定是JVM 唯一的,而是取决于此“static”成员的类型?
   发表时间:2007-04-16  
对一个新实例把旧实例替掉。。。。
0 请登录后投票
   发表时间:2007-04-16  
至少这个数是针对每个线程的
0 请登录后投票
   发表时间:2007-04-16  
ThreadLocal 是个容器,可以简单理解成hashmap,
key就是线程,值就是当前线程能够得到的东西.

有时间在这里乱猜测,还不如认真仔细读下 ThreadLocal 的源代码!!!

0 请登录后投票
   发表时间:2007-04-16  
再写几个单元测试验证一下想法。
0 请登录后投票
   发表时间:2007-04-16  
其实,我虽然有疑问,也是倾向于认为“static”的“ThreadLocal”成员在 JVM 里面是多个的。

Java源码没看过,但“ThreadLocal”的参考实现看过,基本上就是 JVM 里面的一个Map,key 就是当前的 thread,value 就是“ThreadLocal”变量。照这样看来,“ThreadLocal”成员,无论“static”与否,在 JVM 里面总是多个的。

我的疑问,主要在于Java编译器以及JVM在这种既“static”又“ThreadLocal”的情况下的处理办法。我自己一直在想办法,多学些扎实的基础。基础扎实些,总是好的:)
0 请登录后投票
   发表时间:2007-04-17  
这个不难的,看看源代码就明白了。static的ThreadLocal对象在同一个JVM下同一个ClassLoader中只有一个,不然java语言就乱了。

这个ThreadLocal的内部成员只有一个,int threadLocalHashCode,还是个final。这个ThreadLocal,只是提供了对thread local storage的操作,而不含有数据。

那么thread local的数据在哪里呢?在Thread对象里。

去看看Thread的源代码,第157行,

ThreadLocal.ThreadLocalMap threadLocals = null;


ThreadLocal类里面有个static类,ThreadLocalMap,这个类内部是用array实现的。

Thread对象是由操作系统创建的,初始threadLocals为null。

第一次使用ThreadLocal的get()时,如果threadLocals为null,创建个新的ThreadLocal.ThreadLocalMap对象。

下面是ThreadLocal里相对的代码,为了增强可读性我编辑了一下。


public T get() {
  Thread t = Thread.currentThread();
  ThreadLocalMap map = t.threadLocals;
  if (map != null)
    return (T)map.get(this);

  // Maps are constructed lazily.  if the map for this thread
  // doesn't exist, create it, with this ThreadLocal and its
  // initial value as its only entry.
  T value = initialValue();
  t.threadLocals = new ThreadLocalMap(this, firstValue);
  return value;
}



ThreadLocal实际上是当map key使,这个key是个int,hash混了一把后生成。
0 请登录后投票
   发表时间:2007-04-17  
非典型程序员 写道
public class SampleClass  
{  
    public static final ThreadLocal session = new ThreadLocal();  
    ...
}


以上这段代码,一个普通的类,里面一个static成员,成员类型为“ThreadLocal”,并且是final的。

通常我们很熟悉,类里面“static final”的东东都是JVM 唯一的,可以用来放一些常量。

但是,现在,按照“ThreadLocal”的定义,每一个执行到此语句的thread都会得到自己的一个“session”实例。这也是我们用来解决 Hibernate open session in view 的办法。

那么,请教了,在这种既“static”,又“ThreadLocal”的情况下,整个 JVM 里面的“session”实例,到底是单个还是多个呢?

如果是多个,是否可以说,Java类的“static”成员将不一定是JVM 唯一的,而是取决于此“static”成员的类型?


“session”实例是单个,里面只有一个数据,private final int threadLocalHashCode.

所有的ThreadLocal的对象,这个threadLocalHashCode值都不一样。这个hash code是用来当map key用的。实现方法也不难。

  private final int threadLocalHashCode = nextHashCode();

  private static int nextHashCode = 0;

  private static final int HASH_INCREMENT = 0x61c88647;

  private static synchronized int nextHashCode() {
    int h = nextHashCode;
    nextHashCode = h + HASH_INCREMENT;
    return h;
  }


问题解完,星星拿来,
0 请登录后投票
   发表时间:2007-04-17  
初级会员没有星给你个4星
0 请登录后投票
   发表时间:2007-04-17  
非常感谢 bigpanda 的详细回答!有些细节还不是很懂,比如说原来以为 Map 的 key 应该是当前 Thread,但现在看来应该是 ThreadLocal??

无论如何,我马上写了一个测试,发现 bigpanda 是正确的!

public class ThreadLocalTest {
    private static final ThreadLocal testThreadLocal = new ThreadLocal();

    private static class TestThread implements Runnable {
        private ThreadLocal threadLocal;
        public TestThread(ThreadLocal threadLocal) {
            this.threadLocal = threadLocal;
            this.threadLocal.set(new Object());
        }
        public void run() {
            System.out.println("==========");
            System.out.println("ThreadLocal object passed in: "
                    + System.identityHashCode(threadLocal));
            System.out.println("ThreadLocal object content: "
                    + System.identityHashCode(threadLocal.get()));
            System.out.println("==========");
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 6; i ++) {
            new Thread(new TestThread(testThreadLocal)).run();
        }
    }

}


结果,只有一个 threadLocal 实例,但 threadLocal.get() 的结果为多个,且对应多个 Thread 的!

嘻嘻,可惜还是新手,不能送星星~~
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics