测试代码:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class SimpleDateFormatTest {
//这里只创建了一个对象(该对象拥有共享的成员变量protected Calendar calendar;)
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest"));
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000));
public void test() {
System.out.println("================================1");
int i = 0;
while (true) {
i++;
System.out.println("start................");
poolExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println("run................");
String dateString = simpleDateFormat.format(new Date());
try {
Date parseDate = simpleDateFormat.parse(dateString);
String dateString2 = simpleDateFormat.format(parseDate);
System.out.println(dateString.equals(dateString2));
if(!dateString.equals(dateString2)){
return ;
}
System.out.println("runEnd................");
} catch (ParseException e) {
e.printStackTrace();
}
}
});
System.out.println("end................");
if(i==20){
return;
}
}
}
public static void main(String[] args) {
SimpleDateFormatTest sdft = new SimpleDateFormatTest();
sdft.test();
}
}
输出:
true
false
true
true
false
出现了false,说明线程不安全。
public class TestdateString {
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws ParseException {
String dateString = simpleDateFormat.format(new Date());
Date parseDate = simpleDateFormat.parse(dateString);
String dateString2 = simpleDateFormat.format(parseDate);
System.out.println(dateString.equals(dateString2));
}
}
# 截取部分SimpleDateFormat 代码
# 截取SimpleDateFormat 部分代码分析线程不安全问题
public class SimpleDateFormat extends DateFormat {
...........................
................................
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo,
FieldPosition pos)
{
pos.beginIndex = pos.endIndex = 0;
return format(date, toAppendTo, pos.getFieldDelegate());
}
// Called from Format after creating a FieldDelegate
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);
//解析,这里的calendar 来自父类DateFormat 的成员变量calendar ,(只单例创建了一个对象????,被所有线程共享??? 所以有线程安全问题。)
boolean useDateFormatSymbols = useDateFormatSymbols();
for (int i = 0; i < compiledPattern.length; ) {
int tag = compiledPattern[i] >>> 8;
int count = compiledPattern[i++] & 0xff;
if (count == 255) {
count = compiledPattern[i++] << 16;
count |= compiledPattern[i++];
}
switch (tag) {
case TAG_QUOTE_ASCII_CHAR:
toAppendTo.append((char)count);
break;
case TAG_QUOTE_CHARS:
toAppendTo.append(compiledPattern, i, count);
i += count;
break;
default:
subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
break;
}
}
return toAppendTo;
}
....................
}
截取DateFormat 类部分代码:
package java.text;
public abstract class DateFormat extends Format {
protected Calendar calendar;
protected NumberFormat numberFormat;
public final static int ERA_FIELD = 0;
public final StringBuffer format(Object obj, StringBuffer toAppendTo,
FieldPosition fieldPosition)
{
if (obj instanceof Date)
return format( (Date)obj, toAppendTo, fieldPosition );
else if (obj instanceof Number)
return format( new Date(((Number)obj).longValue()),
toAppendTo, fieldPosition );
else
throw new IllegalArgumentException("Cannot format given Object as a Date");
}
//抽象方法
public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
FieldPosition fieldPosition);
public final String format(Date date)
{
return format(date, new StringBuffer(),
DontCareFieldPosition.INSTANCE).toString();
}
........................
}
Calendar类
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
................
@SuppressWarnings("ProtectedField")
protected long time;
@SuppressWarnings("ProtectedField")
protected boolean isTimeSet;
@SuppressWarnings("ProtectedField")
protected boolean areFieldsSet;
transient boolean areAllFieldsSet;
public final void setTime(Date date) {
setTimeInMillis(date.getTime());
}
public void setTimeInMillis(long millis) {
// If we don't need to recalculate the calendar field values,
// do nothing.
if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
&& (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
return;
}
time = millis;
isTimeSet = true;
areFieldsSet = false;
computeFields();
areAllFieldsSet = areFieldsSet = true;
}
................
}