首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。
另外,说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通过ThreadLocal.set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行ThreadLocal.get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。
如果ThreadLocal.set()进去的东西本来就是多个线程共享的同一个对象,那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身,还是有并发访问问题。
下面来看一个hibernate中典型的ThreadLocal的应用:
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}
可以看到在getSession()方法中,首先判断当前线程中有没有放进去session,如果还没有,那么通过sessionFactory().openSession()来创建一个session,再将session set到线程中,实际是放到当前线程的ThreadLocalMap这个map中,这时,对于这个session的唯一引用就是当前线程中的那个ThreadLocalMap(下面会讲到),而threadSession作为这个值的key,要取得这个session可以通过threadSession.get()来得到,里面执行的操作实际是先取得当前线程中的ThreadLocalMap,然后将threadSession作为key将对应的值取出。这个session相当于线程的私有变量,而不是public的。
显然,其他线程中是取不到这个session的,他们也只能取到自己的ThreadLocalMap中的东西。要是session是多个线程共享使用的,那还不乱套了。
试想如果不用ThreadLocal怎么来实现呢?可能就要在action中创建session,然后把session一个个传到service和dao中,这可够麻烦的。或者可以自己定义一个静态的map,将当前thread作为key,创建的session作为值,put到map中,应该也行,这也是一般人的想法,但事实上,ThreadLocal的实现刚好相反,它是在每个线程中有一个map,而将ThreadLocal实例作为key,这样每个map中的项数很少,而且当线程销毁时相应的东西也一起销毁了,不知道除了这些还有什么其他的好处。
总之,ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。归纳了两点:
1。每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
2。将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。
当然如果要把本来线程共享的对象通过ThreadLocal.set()放到线程中也可以,可以实现避免参数传递的访问方式,但是要注意get()到的是那同一个共享对象,并发访问问题要靠其他手段来解决。但一般来说线程共享的对象通过设置为某类的静态变量就可以实现方便的访问了,似乎没必要放到线程中。
ThreadLocal的应用场合,我觉得最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。
http://www.iteye.com/topic/103804
一个项目里面用到的ThreadLocal解决分页传参数的问题
public class SystemContext {
//分页
private static ThreadLocal offset = new ThreadLocal();
//每页的数量
private static ThreadLocal pagesize = new ThreadLocal();
public static void setOffset(int offsetValue){
offset.set(offsetValue);
}
public static int getOffset(){
Integer i = (Integer) offset.get();
if(i==null){
i = 0;
}
return i;
}
public static void delOffset(){
offset.remove();
}
public static void setPagesize(int pagesizeValue){
pagesize.set(pagesizeValue);
}
public static int getPagesize(){
Integer i = (Integer) pagesize.get();
if(i==null){
i = 10;
}
return i;
}
public static void delPagesize(){
pagesize.remove();
}
}
再写了一个Filter,在这个里面获取offset,pagesize参数,并放到当前线程里面,这样层与层之间就不用传分页的参数了
public class PagerFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
SystemContext.setOffset(this.getOffet(request));
SystemContext.setPagesize(this.getPagesize(request));
chain.doFilter(request, servletResponse);
SystemContext.delOffset();
SystemContext.delPagesize();
}
private int getOffet(HttpServletRequest request){
int offset = 0;
try {
offset = Integer.parseInt(request.getParameter("pager.offset"));
} catch (RuntimeException e) {
}
return offset;
}
private int getPagesize(HttpServletRequest request){
int pagesize = 10;
return pagesize;
}
public void init(FilterConfig arg0) throws ServletException {
}
}
到了分页处理的时候,这样就获得分页的参数了
SystemContext.getOffset(),SystemContext.getPagesize()
分享到:
相关推荐
本资料主要聚焦于两种设计模式以及Java中的ThreadLocal特性。 首先,我们来探讨单例模式。单例模式是一种确保一个类只有一个实例,并提供全局访问点的设计模式。在Java中,通常通过私有构造函数、静态工厂方法或...
这种设计模式避免了在多线程环境中直接操作共享资源可能带来的线程安全问题。 #### 四、ThreadLocal的生命周期与内存管理 值得注意的是,`ThreadLocal`变量的生命周期与线程的生命周期紧密关联。当线程结束时,与...
- 当你对ThreadLocal进行`set()`操作时,实际上是将值放入了当前线程的ThreadLocalMap中,键是ThreadLocal对象本身,值是你设置的对象。 - 当你调用`get()`时,它会查找当前线程的ThreadLocalMap,找到对应的键(即...
这个设计模式在多线程编程中尤其有用,因为它避免了传统的同步机制,如synchronized和Lock,从而提高了并发性能。 首先,我们要明确ThreadLocal并不是一个线程局部变量,而是一个类,它提供了一个全局的引用,但是...
通过代理模式实现文件服务的分布式管理,通过策略模式简化逻辑,通过ThreadLocal处理会话,通过工厂模式实现支付渠道切换,以及通过状态模式处理订单变更,这些都是在软件设计中常用且重要的设计模式。理解并熟练...
#### 三、具体设计模式的深入理解 **4. 使用工厂模式的原因是什么?** - 工厂模式允许在一个类的实例化过程中延迟具体的类型决策,提高了代码的灵活性和可扩展性。 - 当系统中有多个产品等级结构时,可以使用工厂...
本资料包含的源代码将深入探讨各种多线程设计模式,帮助开发者理解和应用这些模式。 一、线程基础 在Java中,可以通过实现`Runnable`接口或继承`Thread`类来创建线程。`Runnable`接口允许你将任务逻辑封装在一个类...
Java多线程设计模式是构建高并发、高性能应用的关键技术之一。这些模式通过优化资源利用、提高程序可读性和可维护性,使并发编程更加高效和安全。...理解并熟练运用这些设计模式,对于提升Java并发编程的能力至关重要。
通过阅读“java多线程设计模式详解[1].part1.rar”和“java多线程设计模式详解[1].part2.rar”这两个部分,你将能够深入理解这些模式的原理和实践。而“xml”文件可能是相关资料的配置文件或索引,用于辅助理解和...
本课程“实战Java高并发程序设计模式”旨在深入探讨如何利用Java技术来设计和实现能够处理大量并发请求的应用。通过观看这个视频教程,你将有机会学习到一系列关键知识点,包括但不限于: 1. **并发基础**:了解...
总结来说,Java事务模板设计模式结合ThreadLocal,提供了一种高效、健壮的事务管理策略。它减少了代码的重复性,提高了代码的可读性和可维护性,同时通过ThreadLocal解决了并发环境下的事务隔离问题。理解并熟练应用...
Java多线程设计模式是Java编程中不可或缺的一部分,它涉及到如何在并发环境下高效、安全地组织代码...阅读提供的"java多线程设计模式详解.pdf"和"Java多线程设计模式源码"文件,将能更深入地理解这些模式的实际运用。
本文将深入探讨Java多线程设计模式,帮助开发者理解和应用这些模式。 1. **单例模式**: 在多线程环境中,单例模式的实现需要考虑线程安全问题。传统的双重检查锁定(Double-Checked Locking)和静态内部类...
本教程将深入探讨六个关键的并发设计模式,帮助开发者更好地理解和应用这些模式。 1. **优雅终止线程的设计模式**:在Java中,确保线程能够优雅地停止是非常重要的,以防止资源泄漏或不完整的操作。这通常通过设置...
理解并熟练运用这些设计模式能极大地提高代码的可读性、可维护性和可扩展性。 在这个主题中,标签提到了“源码”,这可能意味着我们将进一步研究Java多线程和设计模式在实际项目或开源库中的应用。例如,Spring框架...
在大型分布式系统和高性能应用中,理解和熟练掌握多线程设计模式至关重要。本资源提供了详细的Java多线程设计模式详解,包括PDF文档和源代码,使得学习过程更加直观和实践性强。 首先,我们要理解什么是多线程。在...