运用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用作全局变量,因为它们只在创建它们的线程内有效,无法跨线程共享。 - 谨慎处理生命周期管理,尤其是在静态变量中使用ThreadLocal,确保在不再需要时正确清理,防止内存泄漏。 6. **应用场景...
ThreadLocal是Java中的一个线程局部变量,它为每个线程都提供了一个独立的变量副本,各个线程可以独立地改变自己的副本,而不会影响其他线程。ThreadLocal常用于解决多线程环境下数据隔离的问题,例如HTTP请求上下文...
- 不要将ThreadLocal用作全局变量,否则可能导致内存泄漏。 - 使用ThreadLocal时,要特别注意线程结束后的清理工作,防止内存泄漏。 - 避免过度使用ThreadLocal,因为它会为每个线程创建额外的内存开销。 以上就是...
这与传统的全局变量不同,全局变量在所有线程间共享,可能导致数据冲突。 **ThreadLocal的作用和目的:** 1. **数据隔离**:ThreadLocal确保了每个线程都有自己的变量副本,避免了多线程之间的数据竞争,从而提高...
- 使用`ThreadLocal`存储线程私有数据,避免全局变量的干扰。 理解并掌握Java多线程下变量共享的原理和解决方案,有助于编写出高效、稳定的并发程序。在实际开发中,应结合具体业务场景选择合适的同步机制,以达到...
【线程作用域内共享变量】 在Java并发编程中,线程...总之,`ThreadLocal`是一个强大的工具,适用于在特定线程内创建独立的变量副本,从而解决线程安全问题。但使用时需谨慎,合理利用,避免滥用和潜在的内存泄漏问题。
- 尽量避免将ThreadLocal用作长期持有的全局变量,尤其是在静态方法或静态变量中使用。 - 避免过度依赖ThreadLocal,因为它可能导致设计上的复杂性和难以维护的问题。 综上所述,ThreadLocal是Java多线程编程中的一...
- 不要将ThreadLocal用作全局变量,因为这样可能会导致内存泄漏。 - 尽量避免在静态方法中使用ThreadLocal,因为静态方法没有绑定到特定的线程,可能导致预期之外的行为。 8. **TestClinet.java和SequenceNumber....
3. **谨慎使用全局ThreadLocal**:全局的ThreadLocal变量可能导致数据在不同线程间意外共享,应谨慎使用。 4. **注意线程池中的ThreadLocal**:线程池中的线程可能会被重用,若不清理ThreadLocal,可能导致后续任务...
在传统的多线程Web应用中,由于多个线程可能会处理同一个请求,如果直接在全局变量中存储session信息,可能会导致线程安全问题。而ThreadLocal提供了一个线程局部的存储空间,每个线程都有自己的ThreadLocal变量...
ThreadLocal对象本身是全局的,但存储的值是线程局部的。 2. **生命周期管理**:需要注意的是,ThreadLocal变量不会自动被垃圾回收,因为它们并不直接持有任何实际的值,而是持有线程的引用。因此,当不再需要使用...
1. **线程上下文**: `ThreadLocal`常用于存储线程上下文信息,如数据库连接、事务ID、用户会话信息等。这些信息在每个线程内独立,不需同步。 2. **缓存**: 小型的线程局部缓存可以避免频繁的全局访问,提高性能。 ...
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的。若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。 在 Java 中,有状态的 Bean 是非...
例如,如果局部变量引用了非线程安全的对象(如全局变量、静态变量或者共享资源),或者通过某种方式(如闭包)使得局部变量的生命周期超出了其定义的代码块,那么就可能出现线程安全问题。因此,即使变量本身是局部...
当我们创建一个ThreadLocal实例时,实际上是创建了一个全局的键值对存储,这个存储空间与线程相关联,每个线程有自己的独立副本,即使多个线程同时访问同一个ThreadLocal变量,也不会相互干扰。 二、...
ThreadLocal,全称为`java.lang.ThreadLocal`,是Java中用于处理线程局部变量的一个类。它的设计目标是为每个线程提供一个独立的变量副本,使得这些副本只对当前线程可见,从而实现了线程之间的数据隔离。...
3. **避免全局变量**:在多线程环境中,全局变量可能导致数据竞争和同步问题,ThreadLocal可以作为局部化的全局变量,为每个线程提供独立的副本。 使用ThreadLocal的基本操作包括: - **创建ThreadLocal对象**:`...
2. **数据存储**:在没有全局状态或者不希望使用同步机制的情况下,ThreadLocal 可以用来在各个线程间存储局部状态。 3. **生命周期**:ThreadLocal 变量仅在其创建线程内有效,当线程结束时,其存储的值也就被释放...