今天我们来讨论另外一种线程安全的实现方法。如果说互斥同步是多线程间的数据共享,那么线程局部变量就是线程间的数据隔离。ThreadLocal把共享数据的可见范围限制在同一个线程之内,这样无须同步也能实现线程之间数据不争用的问题。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。线程局部变量实现的原理也比较简单:每个线程的Thread对象中都有一个ThreadLocalMap对象,这个map存储了一组以该线程所对应的哈希码ThreadLocal.threadLocalHashCode为键,以线程局部变量为值的K-V值对,每一个线程对象都包含了一个独一无二的threadLocalHashCode值,使用这个值就可以获取相对应的变量了,这个变量就是上文中提到的线程局部变量的副本。
我们来分析一下java中最常用到的日期时间格式化工具类SimpleDateFormat。SimpleDateFormat类用来对日期字符串进行解析和格式化输出,但如果使用不小心会导致非常微妙和难以调试的问题,因为 DateFormat 和 SimpleDateFormat 类都不是线程安全的,以下代码:
public class DateUtil {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String formatDate(Date date) throws ParseException {
return sdf.format(date);
}
public static Date parse(String strDate) throws ParseException {
return sdf.parse(strDate);
}
}
没有使用任何同步手段来确保线程安全,我们使用一个测试用例来测试一下是否运行正常:
@Test