`
txidol
  • 浏览: 52323 次
  • 性别: 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
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics