论坛首页 Java企业应用论坛

关于ThreadLocal模式的体会

浏览 23589 次
该帖已经被评为良好帖
作者 正文
   发表时间:2010-04-23  

[b][/b]

抛出异常的爱 写道
61234865 写道
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?

同次请求的不丢就很了不起了.

 

 第二次请求的时候和第一次请求的时候用的是同一个servlet实例。servlet是线程安全的对同一个servlet的请求容器只会实例会一个对像。

0 请登录后投票
   发表时间:2010-09-10  
niveko 写道
ThreadLocal不是用来解决对象共享访问问题的
我不太同意这个观点,现在比如有如下的代码。这个format方法有2个线程循环的访问,每次访问完可以放回线程池中,但是因为SimpleDateFormat不是线程安全的类,所以这样访问肯定会出现并发的错误!
public class Foo {
	
	static SimpleDateFormat formator = new SimpleDateFormat("yyMMddHHmmss");
	
	public static String format(Date date) {
		return formator.format(date);
	}

}


那么为了避免并发的错误,可以有如下2中方案,1加synchronized,这样每次只有一个线程访问这个方法,对性能有影响
public static synchronized String format(Date date) {
		return formator.format(date);
	}

2,每次调用这个方法就生成一个新的SimpleDateFormat对象,这样会生成大量的对象,对性能不是很好
public static String format(Date date) {
		SimpleDateFormat formator = new SimpleDateFormat("yyMMddHHmmss");
		return formator.format(date);
	}


那么如果用ThreadLocal就可以解决创建大量对象的问题和并发访问的问题,重复利用SimpleDateFormat对象
public class Foo {
	static ThreadLocal local = new ThreadLocal();
	
	public static String format(Date date) {
		SimpleDateFormat formator = (SimpleDateFormat)local.get();
		if (formator == null) {
			formator = new SimpleDateFormat("yyMMddHHmmss");
			local.set(formator);
		}
		return formator.format(date);
	}

}



这个我赞同
0 请登录后投票
   发表时间:2010-09-12  
dominic6988 写道

[b][/b]

抛出异常的爱 写道
61234865 写道
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?

同次请求的不丢就很了不起了.

 

 第二次请求的时候和第一次请求的时候用的是同一个servlet实例。servlet是线程安全的对同一个servlet的请求容器只会实例会一个对像。


开发是分层的,不仅jsp和servlet之间传递参数,包括service层、dao层之间传递
0 请登录后投票
   发表时间:2010-12-04  
比传参作用大吧,传参只在这个线程的一个方法里面有用,但是threadlocal可以贯穿整个线程,每个方法在使用的时候都可以得到,类似于spring opensessiononview吧
0 请登录后投票
   发表时间:2010-12-04  
抛出异常的爱 写道
LucasLee 写道
61234865 写道
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?


这个问题的关键在于在web环境下怎么使用。
一般是使用Filter技术,在web.xml配置好,filter里的伪代码是这样:

doFilter(){
设置threadlocal变量;
filterChain.doFilter();
清除threadlocal变量;
}



这样就保证了在Action、JSP里都可以获得本线程的threadlocal变量。
注意:一次web 请求肯定是由一个线程来完成响应的。

这样的用法就更清析了...
不知道还有可能会出什么问题.....
不想用了新的用法会出什么隐问题

这样用就没问题了
doFilter(){
设置threadlocal变量;
try {
filterChain.doFilter();
}finally {
清除threadlocal变量;}
}
0 请登录后投票
   发表时间:2010-12-05  
“而threadLocal中存储的变量的生命周期只在于当前线程,当前结束,threadLocal中存放的参数也被销毁”
这句话虽然说的没错,但千万不要利用线程销毁来清除ThreadLocal,正确的方法就像前面的doFilter例子那样,谁设置谁要负责清除。
所有服务器环境下都是用线程池缓存线程,由于线程不会(或不会立即)被销毁,ThreadLocal也不会被清除,更严重的问题是被缓存的线程的ThreadLocal不确定的会被用到其他服务请求处理中。
假如用ThreadLocal设置了user,而不及时清除,甚至会发生比较严重的安全问题。
0 请登录后投票
   发表时间:2010-12-05   最后修改:2010-12-05
我也有不明白的地方。

ThreadLocal的本意是配合Thread以一种对象拷贝的方式解决多线程的互斥问题的。各自Thread维护自己的ThreadLocalMap,并以这个ThreadLocal的hashCode为key,用户对象为value。

如果lz用一个static的ThreadLocal,以这个ThreadLocal的hashcode()为key,User为value,并只在同一个线程里发挥作用的话,跟用public static Map,以Thread.currentThread().hashCode()为key,User为value,有什么区别吗?



引用

threadlocal内部貌似是使用了Thread.currentThread().getName()来当做key,在jdk1.5中是一种效率比较低的做法,据说在6.0速度有提升,但是实际中用途也不是很广泛,只有在权限系统或者保存数据库Connection时才会用到。


  额,你听谁说的?? 
JDK1.5的代码貌似如下:

    private static synchronized int nextHashCode() {
        int h = nextHashCode;
        nextHashCode = h + HASH_INCREMENT;
        return h;
    }
0 请登录后投票
论坛首页 Java企业应用版

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