ThreadLocal用处:保存线程的独立变量。对一个线程类(继承自Thread)
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。常用于用户登录控制,如记录session信息。
实现:每个Thread都持有一个TreadLocalMap类型的变量(该类是一个轻量级的Map,功能与map一样,区别是桶里放的是entry而不是entry的链表。功能还是一个map。)以本身为key,以目标为value。
主要方法是get()和set(T a),set之后在map里维护一个threadLocal -> a,get时将a返回。ThreadLocal是一个特殊的容器。
package Thread;
public class ThreadLocalTest {
static class ResourceClass {
public final static ThreadLocal<String> RESOURCE_1 =
new ThreadLocal<String>();
public final static ThreadLocal<String> RESOURCE_2 =
new ThreadLocal<String>();
}
static class A {
public void setOne(String value) {
ResourceClass.RESOURCE_1.set(value);
}
public void setTwo(String value) {
ResourceClass.RESOURCE_2.set(value);
}
}
static class B {
public void display() {
System.out.println(ResourceClass.RESOURCE_1.get()
+ ":" + ResourceClass.RESOURCE_2.get());
}
}
public static void main(String []args) {
final A a = new A();
final B b = new B();
for(int i = 0 ; i < 15 ; i ++) {
final String resouce1 = "线程-" + i;
final String resouce2 = " value = (" + i + ")";
new Thread() {
public void run() {
try {
a.setOne(resouce1);
a.setTwo(resouce2);
b.display();
}finally {
ResourceClass.RESOURCE_1.remove();
ResourceClass.RESOURCE_2.remove();
}
}
}.start();
}
}
}
输出结果为:
线程-0: value = (0)
线程-3: value = (3)
线程-2: value = (2)
线程-4: value = (4)
线程-1: value = (1)
线程-6: value = (6)
线程-5: value = (5)
线程-7: value = (7)
线程-8: value = (8)
线程-9: value = (9)
线程-10: value = (10)
线程-12: value = (12)
线程-13: value = (13)
线程-14: value = (14)
线程-11: value = (11)
ThreadLocal为每一个线程提供一个独立的变量副本,从而隔离了多个线程对访问数据的冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的对象封装,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
jfina框架对此ThreadLocal使用较多一些,很好的解决方案,这里摘录一段Javen的开源ijpay源码,详情请大家去开源网站去阅读了解;jfina框架也特别优秀。
package com.jpay.alipay;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.jpay.ext.kit.StrKit;
public class AliPayApiConfigKit {
private static final ThreadLocal<String> TL = new ThreadLocal<String>();
private static final Map<String, AliPayApiConfig> CFG_MAP = new ConcurrentHashMap<String, AliPayApiConfig>();
private static final String DEFAULT_CFG_KEY = "_default_ijpay_key_";
/**
* 添加支付宝支付配置,每个appId只需添加一次,相同appId将被覆盖
* @param aliPayApiConfig 支付宝支付配置
* @return {AliPayApiConfig} 支付宝支付配置
*/
public static AliPayApiConfig putApiConfig(AliPayApiConfig aliPayApiConfig) {
if (CFG_MAP.size() == 0) {
CFG_MAP.put(DEFAULT_CFG_KEY, aliPayApiConfig);
}
return CFG_MAP.put(aliPayApiConfig.getAppId(), aliPayApiConfig);
}
public static AliPayApiConfig setThreadLocalAliPayApiConfig(AliPayApiConfig aliPayApiConfig) {
return putApiConfig(aliPayApiConfig);
}
public static AliPayApiConfig removeApiConfig(AliPayApiConfig apiConfig) {
return removeApiConfig(apiConfig.getAppId());
}
public static AliPayApiConfig removeApiConfig(String appId) {
return CFG_MAP.remove(appId);
}
public static void setThreadLocalAppId(String appId) {
if (StrKit.isBlank(appId)) {
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
}
TL.set(appId);
}
public static void removeThreadLocalAppId() {
TL.remove();
}
public static String getAppId() {
String appId = TL.get();
if (StrKit.isBlank(appId)) {
appId = CFG_MAP.get(DEFAULT_CFG_KEY).getAppId();
}
return appId;
}
public static AliPayApiConfig getAliPayApiConfig() {
String appId = getAppId();
return getApiConfig(appId);
}
public static AliPayApiConfig getApiConfig(String appId) {
AliPayApiConfig cfg = CFG_MAP.get(appId);
if (cfg == null)
throw new IllegalStateException("需事先调用 AliPayApiConfigKit.putApiConfig(aliPayApiConfig) 将 appId对应的 aliPayApiConfig 对象存入," +
"才可以使用 AliPayApiConfigKit.getAliPayApiConfig() 的系列方法");
return cfg;
}
}