为项目代码做安全扫描,发现了SimpleDateFormat的线程安全问题,在一个Util类的静态方法里,创建了一个SimpleDateFormat对象,然后使用它做时间格式转换,但是SimpleDateFormat不是线程安全的,当发生多线程调用时会发生NumberFormatException: multiple points异常。
因此可以采用ThreadLocal的方式解决。
ThreadLocal是每个线程对于共享变量的本地副本,一般来说,线程与线程间的ThreadLocal里的对象是互相隔离的,这个不一般的情况我们一会再说。
以下代码包含2个共享变量,交由ThreadLocal管理的变量x,线程共享的unsyInt。
public class TestDateFormat {
private static ThreadLocal<Integer> local = new ThreadLocal<Integer>(){
public Integer initialValue(){
return new Integer(0);
}
};
private static Integer unsyInt = 0;
public static Integer getUnsyInt(){
return unsyInt;
}
public static void setUnsyInt(Integer x){
unsyInt = x;
}
public static Integer getLocalInt(){
return local.get();
}
public static void setLocalInt(Integer syx){
local.set(syx);
}
}
线程代码中都获取了这2个变量进行自增操作,然后输出。
public static class TestA extends Thread{
public void run(){
while (true){
try {
//变量
Integer syx = TestDateFormat.getLocalInt();
Integer unsyx = TestDateFormat.getUnsyInt();
//自增操作
unsyx++;
syx++;
//写回数据
TestDateFormat.setLocalInt(syx);
TestDateFormat.setUnsyInt(unsyx);
//输出
System.out.println(Thread.currentThread().getName()+":"+TestDateFormat.getLocalInt());
this.sleep(2000);
System.out.println(Thread.currentThread().getName()+"---Unsyn:"+TestDateFormat.getUnsyInt());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
main方法创建2个TestA的实例并开启两个线程,即可以观察到交给threadLocal管理的syx与线程共享的unsyx之间输出的区别