- ThreadLocal用完后要remove
必须回收自定义的ThreadLocal变量,尤其在线程池场景下,线程经常会被复用,如果不清理自定义的ThreadLocal变量,可能会影响后续业务逻辑和造成内存泄漏等问题。尽量在代理中使用try-finally块进行回收。
/**
* @author jl
* @since 2021/10/11 19:51
* SimpleDateFormat线程安全问题示例
*/
public class SimpleDateFormatDemo {
public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public static Date parse(String StringDateFormat) throws ParseException {
return sdf.parse(StringDateFormat);
}
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
new Thread(()->{
try {
System.out.println(SimpleDateFormatDemo.parse("2021-11-11 11:11:11"));
} catch (ParseException e) {
e.printStackTrace();
}
}).start();
}
}
}
异常1
异常2
异常3
异常4
原因:
cal.clear();会清除别的线程设置的值
解决:
1、加锁,影响性能,不推荐,有其他方式也能解决
2、使用ThreadLocal<SimpleDateFormat>
public class SimpleDateFormatDemo {
public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public static Date parse(String StringDateFormat) throws ParseException {
return sdf.parse(StringDateFormat);
}
public static final ThreadLocal<SimpleDateFormat> thread = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
public static Date parseByThreadLocal(String stringDateFormat) throws ParseException {
return thread.get().parse(stringDateFormat);
}
public static void main(String[] args) {
for (int i = 0; i < 30; i++) {
new Thread(()->{
try {
// System.out.println(SimpleDateFormatDemo.parse("2021-11-11 11:11:11"));
System.out.println(SimpleDateFormatDemo.parseByThreadLocal("2021-11-11 11:11:11"));
} catch (ParseException e) {
e.printStackTrace();
} finally {
thread.remove();
}
}).start();
}
}
}