我这样使用ThreadLocal

ThreadLocal介绍和原理

参见:http://www.iteye.com/topic/103804

ThreadLocal的使用

  • 线程封闭

    多线程环境中用于实现线程封闭,ThreadLocal是比Ad-hoc线程封闭和栈封闭更加规范的做法,更通俗的来说每个线程将变量保存在自己才能看到的Map中,不用考虑会被共享竞争,如:

学习Spring必学的Java基础知识(6)----ThreadLocal

利于ThreadLocal管理Hibernate Session

  • 节省资源

我在封装JDK工具类的时候,采用ThreadLocal避免每次都实例化JDK工具类对象,减少内寸分配和回收,同时也有线程安全,简单DEMO供大家参阅


public class DateUtil
{

	private static ThreadLocal<Date> dateLocal = new ThreadLocal<Date>()
	{

		@Override
		protected Date initialValue()
		{
			return new Date();
		}
	};

	/**
	 * 获取 {@link Date}实例,当前时间
	 * 
	 * @return
	 */
	public static Date getInstance()
	{
		Date date = dateLocal.get();
		date.setTime(System.currentTimeMillis());
		return date;
	}

	/**
	 * 获取 {@link Date}实例,给定的秒设置时间
	 * 
	 * @param time
	 *            秒
	 * @return
	 */
	public static Date getInstance(long time)
	{
		Date date = dateLocal.get();
		date.setTime(time * 1000L);
		return date;
	}

	private DateUtil()
	{
	}
}

  • 参数的灵活传递

1 在设计API的时候难免考虑不周全,如果入参不是像Map、List这种可以动态扩展内容的参数,除了重载,想要增加新的入参是很困难的,当然这种场景比较特殊,这时ThreadLocal就派上用场了,只需要在方法实现中通过调用新参数的ThreadLocal.get方法就可以获得值

2 避免显式传递参数丑陋,随存随取。webservice接口程序中返回值由哪几个部分组成是确定的,一般情况下我们会一个个串行写入元素,也就是说在写入下一个元素前,前面元素的值是不能变动的,但实际情况恰恰不能忍受。如webservice接口规定了返回值为JSON字符串,JSON内元素有二:resultCode和result,resultCode会因为异常、鉴权、通信结果而不同,这个是无法预知的,所以resultCode需要可以灵活的设置,ThreadLocal可以帮助你,见示例代码:


public class BaseExporter
{
	protected ConfigManager configManager;
	protected static final Log LOGGER = LogFactory.getLog(BaseExporter.class);
	static final ThreadLocal<Map<String, Object>> localMap = new ThreadLocal<Map<String, Object>>()
	{

		@Override
		protected Map<String, Object> initialValue()
		{
			return new HashMap<String, Object>();
		}
	};
	static final ThreadLocal<SimpleDateFormat> simpleDateFormatLocal = new ThreadLocal<SimpleDateFormat>()
	{

		@Override
		protected SimpleDateFormat initialValue()
		{
			return new SimpleDateFormat();
		}
	};
	protected UserManager userManager;
	/*
	 * 常量
	 */
	protected final static String RESULT_NULL_OBJECT = "{}";
	protected final static String RESULT_NULL_ARRAY = "[]";
	protected final static String PARAM_PATTERN_ALL = "*";
	protected final static String PARAM_PATTERN_TIME = "yyyy-MM-dd HH:mm:ss";
	protected final static String JSON_KEY_RESULTCODE = "resultCode";
	protected final static String JSON_KEY_RESULT = "result";
	protected final static String JSON_KEY_PARAM_USERNAME = "userName";
	protected final static String JSON_KEY_PARAM_PASSWORD = "password";
	// 结果码-成功
	protected final static String RESULTCODE_SUCESS = "0000";
	// 结果码-异常
	protected final static String RESULTCODE_ERROR_INTERNAL = "9999";
	// 结果码-鉴权
	protected final static String RESULTCODE_FAIL_USER_NOTEXSIT = "0001";
	protected final static String RESULTCODE_FAIL_PASSWORD_ERROR = "0002";
	protected final static String RESULTCODE_FAIL_USER_EXPIRED = "0003";
	protected final static String RESULTCODE_FAIL_IP_ILLGEAL = "0004";
	protected final static String RESULTCODE_FAIL_USER_LOCKED = "0005";
	protected final static String RESULTCODE_FAIL_PERMISSION_DENIED = "0006";
	
 
	/**
	 * 设置结果码
	 * 
	 * @param resultCode
	 */
	protected static void setResultCode(String resultCode)
	{
		localMap.get().put(JSON_KEY_RESULTCODE, resultCode);
	}

	/**
	 * 获取结果码
	 * 
	 * @return
	 */
	protected static String getResultCode()
	{
		return String.valueOf(localMap.get().get(JSON_KEY_RESULTCODE));
	}

	/**
	 * 设置JSON结果
	 * 
	 * @param result
	 */
	protected static void setResult(String result)
	{
		localMap.get().put(JSON_KEY_RESULT, result);
	}

	/**
	 * 获取JSON结果
	 * 
	 * @return
	 */
	protected static String getResult()
	{
		return String.valueOf(localMap.get().get(JSON_KEY_RESULT));
	}

	/**
	 * 组装JSON结果
	 * 
	 * @return
	 */
	protected static String assembleResultJson()
	{
		StringBuilder json = new StringBuilder("{\"");
		json.append(JSON_KEY_RESULTCODE).append("\":\"").append(getResultCode()).append("\",\"").append(JSON_KEY_RESULT).append("\":")
				.append(getResult());
		json.append("}");
		return json.toString();
	}
 
}

使用:

public String queryDevice(String jsonParam)
	{
		JSONObject jsonObject = parseJSONString(jsonParam);
		String userName = jsonObject.getString(JSON_KEY_PARAM_USERNAME);
		String password = jsonObject.getString(JSON_KEY_PARAM_PASSWORD);
		String platName = jsonObject.getString("platName");
		String deviceIP = jsonObject.getString("deviceIP");
		setResult(RESULT_NULL_ARRAY);
		if (validateSignOn(userName, password))
		{
			List<MoInfo> plats = configManager.listPlatformMos();
			MoInfo[] platAllDeviceMos = null;
			List<Device> matchedDevices = new ArrayList<Device>();
			//略...
			if (!matchedDevices.isEmpty())
			{
				try
				{
					setResult(toJSONString(matchedDevices));
				}
				catch (Exception e)
				{
					LOGGER.error("转换JSON异常", e);
					setResultCode(RESULTCODE_ERROR_INTERNAL);
				}
			}
		}
		return assembleResultJson();
	}

ThreadLocal中保存了线程私有的map示例,里面有resultCode和result键值对,通过调用BaseExporter的setter和getter实现随存随取,最后调用assembleResultJson进行JSON字符串的拼装

3 结合动态代理实现资源的自动获取。我在实现redis缓存的时候利用到了这点可以参见git上的代码:AbstractRedisObject.java


目前使用的大概就这么多,个人能力有限难免有错误或遗漏,欢迎大家留言补充








你可能感兴趣的:(我这样使用ThreadLocal)