【JAVA8新的时间与日期 API】- 传统时间格式化的线程安全问题
2021-05-05 16:27
标签:false 线程安全 自己的 sep boolean void span isl source Java8之前的日期和时间API,存在一些问题,最重要的就是线程安全的问题。这些问题都在Java8中的日期和时间API中得到了解决,而且Java8中的日期和时间API更加强大。 以上代码运行会报错: 综上,我们可以看到 SimpleDateFormat 类中的parse 方法,调用了 CalendarBuilder 的 establish(calendar) 方法,并在方法中,对 calendar 对象进行了各种判断及修改,并且这些操作都不是原子操作或同步操作,而这个calendar 对象又是 SimpleDateFormat 的父类 DateFormat 的一个实例变量,所以,在多线程同时调用SimpleDateFormat 的 parse 方法的时候,就会出现线程安全问题。 1. 将 SimpleDateFormat 对象定义成局部变量。 2. 加锁。 3. 使用ThreadLocal,每个线程都拥有自己的SimpleDateFormat对象副本。 【JAVA8新的时间与日期 API】- 传统时间格式化的线程安全问题 标签:false 线程安全 自己的 sep boolean void span isl source 原文地址:https://www.cnblogs.com/y3blogs/p/13172896.html
传统时间格式化的线程安全问题
示例:
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
public class TestOldSimpleDateFormat {
public static void main(String[] args) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Callable
pool.shutdown();
}
}报错缘由:取部分源码解释
/**
* SimpleDateFormat 类的 parse 方法 部分源码
*/
public Date parse(String source) throws ParseException
{
ParsePosition pos = new ParsePosition(0);
Date result = parse(source, pos);
if (pos.index == 0)
throw new ParseException("Unparseable date: \"" + source + "\"" ,
pos.errorIndex);
return result;
}
public Date parse(String text, ParsePosition pos)
{
// 省略上面诸多代码
Date parsedDate;
CalendarBuilder calb = new CalendarBuilder();
try {
//这里这个 calendar 对象是 SimpleDateFormat 类的父类 DateFormat 中的属性 : protected Calendar calendar;
parsedDate = calb.establish(calendar).getTime();//这个 calb.establish(calendar) 方法中,这个方法中的主要步骤不是原子操作,并且会对 calendar 对象进行修改,所以在多线程环境下就会出现线程安全问题。
// 省略下面面诸多代码
}
catch (IllegalArgumentException e) {
//省略.........................
return null;
}
return parsedDate;
}
Calendar establish(Calendar cal) {
boolean weekDate = isSet(WEEK_YEAR)
&& field[WEEK_YEAR] > field[YEAR];
if (weekDate && !cal.isWeekDateSupported()) {
// Use YEAR instead
if (!isSet(YEAR)) {
set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
}
weekDate = false;
}
cal.clear();
// Set the fields from the min stamp to the max stamp so that
// the field resolution works in the Calendar.
for (int stamp = MINIMUM_USER_STAMP; stamp ) {
for (int index = 0; index ) {
if (field[index] == stamp) {
cal.set(index, field[MAX_FIELD + index]);
break;
}
}
}
if (weekDate) {
int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
int dayOfWeek = isSet(DAY_OF_WEEK) ?
field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
if (dayOfWeek >= 8) {
dayOfWeek--;
weekOfYear += dayOfWeek / 7;
dayOfWeek = (dayOfWeek % 7) + 1;
} else {
while (dayOfWeek ) {
dayOfWeek += 7;
weekOfYear--;
}
}
dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
}
cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
}
return cal;
}
针对以上异常,JAVA8之前的解决办法:
示例(加锁):
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Callable
示例(ThreadLocal):
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormatThreadLocal {
private static final ThreadLocal
pool.shutdown();
} }
JAVA8的解决办法:使用新的API(DateTimeFormatter 和 LocalDate )
示例:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class TestOldSimpleDateFormat {
public static void main(String[] args) throws Exception {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Callable
文章标题:【JAVA8新的时间与日期 API】- 传统时间格式化的线程安全问题
文章链接:http://soscw.com/index.php/essay/82809.html