`
txidol
  • 浏览: 54786 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

【ThreadLocal模式】线程上的全局变量

 
阅读更多

运用ThreadLocal模式的场景

1.频繁创建生命周期短暂的实例(或者实例化代价昂贵)导致性能低下

2.需要线程安全,使用‘synchronized’线程同步同样导致性能低下

以下是Tim Cull的博文“SimpleDateFormat: Performance Pig”解决满足这一需求采用ThreadLocal模式的案列

Tim Cull 写道:

Tim Cull碰到一个SimpleDateFormat带来的严重的性能问题,该问题主要有SimpleDateFormat引发,创建一个 SimpleDateFormat实例的开销比较昂贵,解析字符串时间时频繁创建生命周期短暂的实例导致性能低下。即使将 SimpleDateFormat定义为静态类变量,貌似能解决这个问题,但是SimpleDateFormat是非线程安全的,同样存在问题,如果用 ‘synchronized’线程同步同样面临问题,同步导致性能下降(线程之间序列化的获取SimpleDateFormat实例)。

Tim Cull使用Threadlocal解决了此问题,对于每个线程SimpleDateFormat不存在影响他们之间协作的状态,为每个线程创建一个SimpleDateFormat变量的拷贝或者叫做副本

public class DateUtil {  
    
    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";  
      
    @SuppressWarnings("rawtypes")  
    private static ThreadLocal threadLocal = new ThreadLocal() {  
        protected synchronized Object initialValue() {  
            return new SimpleDateFormat(DATE_FORMAT);  
        }  
    };  
  
    public static DateFormat getDateFormat() {  
        return (DateFormat) threadLocal.get();  
    }  
  
    public static Date parse(String textDate) throws ParseException {  
        return getDateFormat().parse(textDate);  
    }  
} 

下面做了 静态计数器(/单例模式) 和ThreadLocal模式计数器 对比结果,证明ThreadLocal模式下是线程安全的,每个线程都有自己的独立副本,线程内各个方法及层次都可以使用该变量,而不用再次实例化或者采用传参【比如Struts的ActionContext】

public class Counter {
	public static Integer number =10;	
}
public class LocalCounter {
	
	public Integer number =10;
	
	private static ThreadLocal<LocalCounter> counter = new ThreadLocal<LocalCounter>(){
		protected synchronized LocalCounter initialValue(){			
			return new LocalCounter();
		}
	};//初始需要覆盖初始化方法,不覆盖第一次调用get方法值为null,使用前需要先调set方法初始化
	
	public static LocalCounter getCounter() {
        return (LocalCounter) counter.get();
	}
		
	public static void setCounter(LocalCounter counterFrom){
		counter.set(counterFrom);
	}	
}

public class ThreadLocalStub extends Thread {
	
	public void run() {	
		for (int i = 0; i < 2; i++) {			
			LocalCounter localCounter = LocalCounter.getCounter();//当前使用时不用再次创建
	
			System.out.println("Thread[" + Thread.currentThread().getName()
					+ "],localCounter=" + localCounter.number++);
			System.out.println("Thread[" + Thread.currentThread().getName()
					+ "],Counter=" + Counter.number++);
		
			LocalCounter.setCounter(localCounter);							
		}
		 nextAdd();
	}
	
	private void nextAdd(){
		LocalCounter localCounter = LocalCounter.getCounter();//当前使用时不用再次创建,线程上共享
		
		System.out.println("Thread[" + Thread.currentThread().getName()
				+ "],localCounter=" + localCounter.number++);
		System.out.println("Thread[" + Thread.currentThread().getName()
				+ "],Counter=" + Counter.number++);
	
		LocalCounter.setCounter(localCounter);	
	}
}

public class ThreadLocalTest {
	public static void main(String[] args) {		
		ThreadLocalStub testThread1 = new ThreadLocalStub();
		ThreadLocalStub testThread2 = new ThreadLocalStub();
		ThreadLocalStub testThread3 = new ThreadLocalStub();
		testThread1.start();
		testThread2.start();
		testThread3.start();
	}
}

运行结果:
Thread[Thread-0],localCounter=10
Thread[Thread-1],localCounter=10
Thread[Thread-0],Counter=10
Thread[Thread-1],Counter=11
Thread[Thread-1],localCounter=11
Thread[Thread-1],Counter=12
Thread[Thread-1],localCounter=12
Thread[Thread-1],Counter=13
Thread[Thread-2],localCounter=10
Thread[Thread-2],Counter=14
Thread[Thread-2],localCounter=11
Thread[Thread-2],Counter=15
Thread[Thread-2],localCounter=12
Thread[Thread-2],Counter=16
Thread[Thread-0],localCounter=11
Thread[Thread-0],Counter=17
Thread[Thread-0],localCounter=12
Thread[Thread-0],Counter=18
分享到:
评论

相关推荐

    ThreadLocal 线程本地变量 及 源码分析.rar_开发_设计

    - 不要将ThreadLocal用作全局变量,因为它们只在创建它们的线程内有效,无法跨线程共享。 - 谨慎处理生命周期管理,尤其是在静态变量中使用ThreadLocal,确保在不再需要时正确清理,防止内存泄漏。 6. **应用场景...

    设计模式及ThreadLocal资料

    ThreadLocal是Java中的一个线程局部变量,它为每个线程都提供了一个独立的变量副本,各个线程可以独立地改变自己的副本,而不会影响其他线程。ThreadLocal常用于解决多线程环境下数据隔离的问题,例如HTTP请求上下文...

    ThreadLocal应用示例及理解

    - 不要将ThreadLocal用作全局变量,否则可能导致内存泄漏。 - 使用ThreadLocal时,要特别注意线程结束后的清理工作,防止内存泄漏。 - 避免过度使用ThreadLocal,因为它会为每个线程创建额外的内存开销。 以上就是...

    Java多线程编程之ThreadLocal线程范围内的共享变量

    这与传统的全局变量不同,全局变量在所有线程间共享,可能导致数据冲突。 **ThreadLocal的作用和目的:** 1. **数据隔离**:ThreadLocal确保了每个线程都有自己的变量副本,避免了多线程之间的数据竞争,从而提高...

    java多线程_java多线程下变量共享_

    - 使用`ThreadLocal`存储线程私有数据,避免全局变量的干扰。 理解并掌握Java多线程下变量共享的原理和解决方案,有助于编写出高效、稳定的并发程序。在实际开发中,应结合具体业务场景选择合适的同步机制,以达到...

    18 线程作用域内共享变量—深入解析ThreadLocal.pdf

    【线程作用域内共享变量】 在Java并发编程中,线程...总之,`ThreadLocal`是一个强大的工具,适用于在特定线程内创建独立的变量副本,从而解决线程安全问题。但使用时需谨慎,合理利用,避免滥用和潜在的内存泄漏问题。

    ThreadLocal原理及在多层架构中的应用

    - 尽量避免将ThreadLocal用作长期持有的全局变量,尤其是在静态方法或静态变量中使用。 - 避免过度依赖ThreadLocal,因为它可能导致设计上的复杂性和难以维护的问题。 综上所述,ThreadLocal是Java多线程编程中的一...

    ThreadLocal的用处

    - 不要将ThreadLocal用作全局变量,因为这样可能会导致内存泄漏。 - 尽量避免在静态方法中使用ThreadLocal,因为静态方法没有绑定到特定的线程,可能导致预期之外的行为。 8. **TestClinet.java和SequenceNumber....

    ThreadLocal_ThreadLocal源码分析_

    3. **谨慎使用全局ThreadLocal**:全局的ThreadLocal变量可能导致数据在不同线程间意外共享,应谨慎使用。 4. **注意线程池中的ThreadLocal**:线程池中的线程可能会被重用,若不清理ThreadLocal,可能导致后续任务...

    使用ThreadLocal管理“session”数据

    在传统的多线程Web应用中,由于多个线程可能会处理同一个请求,如果直接在全局变量中存储session信息,可能会导致线程安全问题。而ThreadLocal提供了一个线程局部的存储空间,每个线程都有自己的ThreadLocal变量...

    ThreadLocal那点事儿编程开发技术共6页.pdf

    ThreadLocal对象本身是全局的,但存储的值是线程局部的。 2. **生命周期管理**:需要注意的是,ThreadLocal变量不会自动被垃圾回收,因为它们并不直接持有任何实际的值,而是持有线程的引用。因此,当不再需要使用...

    ThreadLocal简单Demo

    1. **线程上下文**: `ThreadLocal`常用于存储线程上下文信息,如数据库连接、事务ID、用户会话信息等。这些信息在每个线程内独立,不需同步。 2. **缓存**: 小型的线程局部缓存可以避免频繁的全局访问,提高性能。 ...

    Java 单例模式线程安全问题

    若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的。若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。 在 Java 中,有状态的 Bean 是非...

    局部变量线程安全测试

    例如,如果局部变量引用了非线程安全的对象(如全局变量、静态变量或者共享资源),或者通过某种方式(如闭包)使得局部变量的生命周期超出了其定义的代码块,那么就可能出现线程安全问题。因此,即使变量本身是局部...

    InheritableThreadLocal & ThreadLocal

    当我们创建一个ThreadLocal实例时,实际上是创建了一个全局的键值对存储,这个存储空间与线程相关联,每个线程有自己的独立副本,即使多个线程同时访问同一个ThreadLocal变量,也不会相互干扰。 二、...

    ThreadLocal

    ThreadLocal,全称为`java.lang.ThreadLocal`,是Java中用于处理线程局部变量的一个类。它的设计目标是为每个线程提供一个独立的变量副本,使得这些副本只对当前线程可见,从而实现了线程之间的数据隔离。...

    Python之ThreadLocal共4页.pdf.zip

    3. **避免全局变量**:在多线程环境中,全局变量可能导致数据竞争和同步问题,ThreadLocal可以作为局部化的全局变量,为每个线程提供独立的副本。 使用ThreadLocal的基本操作包括: - **创建ThreadLocal对象**:`...

    Quartz-ThreadLocal.rar

    2. **数据存储**:在没有全局状态或者不希望使用同步机制的情况下,ThreadLocal 可以用来在各个线程间存储局部状态。 3. **生命周期**:ThreadLocal 变量仅在其创建线程内有效,当线程结束时,其存储的值也就被释放...

Global site tag (gtag.js) - Google Analytics