请教ThreadLocal

各位大哥,我是一个只知道埋头设计自己代码疏于学习别人技术的笨家伙,今天来到这里忽然觉得打开了另一个世界的大门,非常感谢。
有一个问题,我一直希望可以在class里象jsp里访问session一样可以访问一些变量而不用在调用时传入,这些变量可以是每个客户访问不同的。例如纪录operator,以便在不同的地方log时不必再一层一层把operatorId传进去。看了一下帖子里提到ThreadLocal,我想这个东西可能是我需要的。我查了java API doc,看到一个例子,不是十分肯定。而且有一点不懂:
public class SerialNum {
// The next serial number to be assigned
private static int nextSerialNum = 0;

private static ThreadLocal serialNum = new ThreadLocal() {
protected synchronized Object initialValue() {
return new Integer(nextSerialNum++);
}
};
public static int get() {
return ((Integer) (serialNum.get())).intValue();
}
}
中的:
new ThreadLocal() {
protected synchronized Object initialValue() {
return new Integer(nextSerialNum++);
}
};

是什么意思?定义一个新类吗,明明只有一个函数initialValue(),为什么下面又调用get方法。看起来更象是继承,initialValue()更象是覆盖,是这样吗?

有ThreadLocal可以让我参考吗?

非常感谢,想澄清两个概念,在类里又调用别的类应该都是一个在Thread里,对吧,如果jsp执行结束,那么thread应该也结束。即使postback也不是同一个thread了,是这样吗?

一个jsp里调用分别调用的几个类也都是运行在一个thread里吧!

应该说正确,如果不考虑线程池。

这段代码
----------
Session s = (Session) session.get();
if (s == null) {
……
}
----------
会不会有问题,
session.get()可能返回null,
而对null类型转换:(Session)null会不会抛出异常,
因而根本执行不到session.get()?

<<而对null类型转换:(Session)null会不会抛出异常,>>

Don't worry. ^-^
-Jevang

不会。

跨域共享同一个对象,如果该对象是线程安全的,即不同的thread可以使用同一个对象的话,比如SessionFactory,可以使用class static attribute。只要在同一个JVM里面,任何被调用的代码都可以取到该对象。

如果需要跨域共享的对象不是线程安全的,即不同的thread必须hold自己单独的对象实例,比如Session,可以使用ThreadLocal,只要在同一thread里面任何被调用的代码都可以取到该对象。

一个ThreadLocal变量类似一个HashMap,它的key集合就是Thread.currentThread(),它的value集合就是要跨域共享的对象。当代码从threadLocal变量get()来取对象的时候,就是以代码运行所在的currentThread为key,去找它对应的value共享对象。因而在一个thread里面,任何被该thread调用到的类,方法代码都可以取到同一个跨域共享对象。而不同的thread则取到不同的对象。

to sprsong

"一直希望可以在class里象jsp里访问session一样可以访问一些变量而不用在调用时传入"

如果你是这个目的,我认为建立一个singleton模式的类就可以了,HTTpSession的实现也类似一个singleton的hashtable。

不过,当然自己实现singleton类,还需要考虑多线程情况下的同步问题,还有DCL问题,jdk 1.4 的ThreadLocal解决了线程池的DCL问题,而且性能提高比较大,属于线程安全型的。

如果不考虑同步问题,自己实现singlelton的性能要比ThreadLocal来得快。

当然,还有一个技术对象池可以供你选择。

但是一旦这些技术都搞上,还不如将普通class都换成EJB,上面这些技术烦恼就会远离你而去。

thank banq

>还不如将普通class都换成EJB

是指使用“状态bean”吗。我以前曾经发现第二次jsp调用同一个无状态bean时好像变量数值可以保留的。加入我在class里声明变量str,在所有的函数里只有str+=的操作,那么当我刷新页面时str的输出会累加。


>如果你是这个目的,我认为建立一个singleton模式的类就可以了。

您的意思是否是类似实现一个静态的map,用一个能区别当前thread的对象作为key。我看到IBM声明用当前thread作为key是一种Bad implementation。那么用什么做key好一点呢?

sorry,

>如果你是这个目的,我认为建立一个singleton模式的类就可以了,
>HTTpSession的实现也类似一个singleton的hashtable。

刚才没仔细想,singleton的hashtable应该是指取对象时,没有就新建,有了就返回当前。那么我怎么把不同tread的值区别开?
如果我能够写一个区别各个客户连接(相当于httpsession的生命周期)而不是thread的singleton的hashtable,是不是就可以完全取代httpsession了。
想要偷懒真不是件容易事。

"如果我能够写一个区别各个客户连接(相当于httpsession的生命周期)而不是thread的singleton的hashtable,是不是就可以完全取代httpsession了。"

是这样,从实际角度说,应该是基于区别客户每个连接,而不是基于线程,线程是瞬间,很难于把握的,除非是要实现并行处理的一些问题,尽量回避线程。

EJB的有状态Session Bean也可以实现基于session的应用,具体选择怎么选择看你的决定。

Java的问题就是给我们的选择太多了,靠。这就象“民主”,没民主要民主,有了民主就听到一片吵闹,让人心烦,无从选择啊。

哈哈,是这样,这个世界上往往没有达不到的目标(当然是精神正常人制定的目标),困难时可以独辟蹊径。但我们往往在岔路面前踌躇不前,甚至铸下大错。我经常在实现一个功能时在几个方案间拿不定主意,总害怕选择的失误给以后带来工作量,总害怕没有找到最好的选择。

有个要写基于区别客户每个连接的singleton有两个难点:
1、如何区别客户每个连接,关键字用什么,如果不得不用Session保存key,那么还是脱离不了Session。(难度:想不到解决办法)
2、连接结束时的资源回收,似乎要覆盖一个函数,我记不得了。(难度:可以解决,但要查资料)

呵呵 和我一样,在选择时是最痛苦,总是害怕没有找到最好的选择。

基于区别每个客户连接,可以以requestId来区分,requestID是由服务器产生响应后送到客户端,客户端连接服务器时再送回来。
这个办法我是在测试性能时用过。

什么问题至于这么复杂啊?能用session解决就用session解决啊。