Re: https://mp.weixin.qq.com/s/i4BdU5vsN_AEBK-QRxQF0w
一、SimpleDateFormat
1.1 日期转换
Date data = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dataStr = sdf.format(data);
System.out.println(dataStr);
System.out.println(sdf.parse(dataStr));
1.2 线程不安全
多线程访问同一个静态 SimpleDateFormat 不安全:
/** * @author Hollis */
public class Main {
/**
* 定义一个全局的SimpleDateFormat
*/
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 使用ThreadFactoryBuilder定义一个线程池
*/
private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();
private static ExecutorService pool = new ThreadPoolExecutor(5, 200,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
/**
* 定义一个CountDownLatch,保证所有子线程执行完之后主线程再执行
*/
private static CountDownLatch countDownLatch = new CountDownLatch(100);
public static void main(String[] args) {
//定义一个线程安全的HashSet
Set<String> dates = Collections.synchronizedSet(new HashSet<String>());
for (int i = 0; i < 100; i++) {
//获取当前时间
Calendar calendar = Calendar.getInstance();
int finalI = i;
pool.execute(() -> {
//时间增加
calendar.add(Calendar.DATE, finalI);
//通过simpleDateFormat把时间转换成字符串
String dateString = simpleDateFormat.format(calendar.getTime());
//把字符串放入Set中
dates.add(dateString);
//countDown
countDownLatch.countDown();
});
}
//阻塞,直到countDown数量为0
countDownLatch.await();
//输出去重后的时间个数
System.out.println(dates.size());
}
}
原因在于 format 方法使用了类的成员变量:
parse 有同样的问题:
1.3 解决线程安全问题
使用局部变量
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
给 SimpleDateFormat 对象加锁
pool.execute(() -> {
//加锁
synchronized (simpleDateFormat) {
//时间增加
calendar.add(Calendar.DATE, finalI);
//通过simpleDateFormat把时间转换成字符串
String dateString = simpleDateFormat.format(calendar.getTime());
//把字符串放入Set中
dates.add(dateString);
//countDown
countDownLatch.countDown();
}
});
使用 ThreadLocal
/**
* 使用ThreadLocal定义一个全局的SimpleDateFormat
*/
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
//用法
String dateString = simpleDateFormatThreadLocal.get().format(calendar.getTime());
使用 DateTimeFormatter(Java8)
//解析日期
String dateStr= "2016年10月25日";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
LocalDate date = LocalDate.parse(dateStr, formatter);
//日期转换为字符串
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm a");
String nowStr = now.format(formatter);
System.out.println(nowStr);
[