自从碰到N多个性能问题后,看是注意使用ThreadLocal的使用,本章只是体现如何使用ThreadLocal,ThreadLocal在性能方面的提高以及在内存分配方面的优势不再讨论范围内。
ThreadLocal的扼要
一个线程有它独立的流程的stack,在web的应用容器中都有Thread Pool,因为线程的创建都是重量级的消耗。
weblogic、glassfish、jboss都是允许你调解Pool。
需要了解ThreadLocal,那先假设我们自己订制一个简单的ThreadLocal
import java.util.HashMap; import java.util.Map; public class CustomThreadLocal { private static Map threadMap = new HashMap(); public static void add(Object object) { threadMap.put(Thread.currentThread(), object); } public static void remove(Object object) { threadMap.remove(Thread.currentThread()); } public static Object get() { return threadMap.get(Thread.currentThread()); } }
public class ThreadContext { private String userId; private Long transactionId; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public Long getTransactionId() { return transactionId; } public void setTransactionId(Long transactionId) { this.transactionId = transactionId; } public String toString() { return 'userId:' + userId + ',transactionId:' + transactionId; } }
public class ThreadLocalMainSampleEx1 { public static void main(String[] args) { new Thread(new Runnable() { public void run() { ThreadContext threadContext = new ThreadContext(); threadContext.setTransactionId(1l); threadContext.setUserId('User 1'); CustomThreadLocal.add(threadContext); //here we call a method where the thread context is not passed as parameter PrintThreadContextValues.printThreadContextValues(); } }).start(); new Thread(new Runnable() { public void run() { ThreadContext threadContext = new ThreadContext(); threadContext.setTransactionId(2l); threadContext.setUserId('User 2'); CustomThreadLocal.add(threadContext); //here we call a method where the thread context is not passed as parameter PrintThreadContextValues.printThreadContextValues(); } }).start(); } }
当我CustomThreadLocal.get()时候,它使用通过内部map去寻找到它自身独有Context上下文信息。
那如果采纳使用ThreadLocal呢?
public class ThreadContext { private String userId; private Long transactionId; private static ThreadLocal threadLocal = new ThreadLocal(){ @Override protected ThreadContext initialValue() { return new ThreadContext(); } }; public static ThreadContext get() { return threadLocal.get(); } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public Long getTransactionId() { return transactionId; } public void setTransactionId(Long transactionId) { this.transactionId = transactionId; } public String toString() { return 'userId:' + userId + ',transactionId:' + transactionId; } }
是不是挺简单的使用的呢?如果配置上Pool,是不是挺完美的,在N多框架中都基本上采用上述方式,ibatis、BoneCP等都是携带
ThreadLocal另外用处是对于非线程安全的实例,通过ThreadLocal的包装同样能够保证并发下的安全。
package ccs.progest.javacodesamples.threadlocal.ex4; import java.text.SimpleDateFormat; import java.util.Date; public class ThreadLocalDateFormat { // SimpleDateFormat is not thread-safe, so each thread will have one private static final ThreadLocal formatter = new ThreadLocal() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat('MM/dd/yyyy'); } }; public String formatIt(Date date) { return formatter.get().format(date); } }
ThreadLocal的应用场景
1.类似于userId、tractionId、以及session等
2.为了保证每个线程更好独享自己实例信息