标签:mtk btv SOS i++ 不必要 ann 控制 leo otf
// Don‘t do this!
String s = new String("stringette");
// 优化版
String s = "stringette";
第二行代码每次被执行的时候都创建一个新的String实例,实属画蛇添足。传递给String构造器的参数“stringette”本身就是一个String实例,功能等价于构造器创建的所有对象。第四行代码只用了一个String实例,而非每次被创建的时候都创建一个新的实例,并且,对于所有在同一台虚拟机中运行的代码,只要他们包含相同的字符串字面常量,对象“stringette”就会被重用。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class DateUtils {
// private static final Log logger = LogFactory.getLog(DateUtils.class);
public static final String YYYYMMDHHMMSS = "yyyy-MM-dd HH:mm:ss";
private static final SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDHHMMSS);// 臭味道
private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern(YYYYMMDHHMMSS);
private static ThreadLocal<SimpleDateFormat> local = new ThreadLocal<SimpleDateFormat>();
/**
* 线程不安全
*/
public static String format(Date date) throws ParseException {
return sdf.format(date);
}
/** * 线程不安全 * parse 并不是一个原子性的操作 */
public static Date parse(String strDate) throws ParseException {
return sdf.parse(strDate);
}
/**
* 线程安全
* 使用 DateTimeFormatter
*/
public static String safeDtfFormatDate(String dateStr) throws ParseException {
LocalDate date1 = LocalDate.parse(dateStr, dtf);
return dtf.format(date1);
}
/**
* 线程安全
* 使用 DateTimeFormatter
*/
public static Date safeDtfParse(String strDate) throws ParseException {
return (Date) dtf.parse(strDate);
}
/** * 线程安全 * 将SimpleDateFormat定义成局部变量 */
public static Date safeParseDate(String strDate, String pattern) {
Date date = null;
try {
if (pattern == null) {
pattern = YYYYMMDHHMMSS;
}
SimpleDateFormat format = new SimpleDateFormat(pattern);
date = format.parse(strDate);
} catch (Exception e) {
// logger.error("parseDate error:" + e);
}
return date;
}
public static Date localParse(String str) throws Exception {
SimpleDateFormat sdf = local.get();
if (sdf == null) {
sdf = new SimpleDateFormat(YYYYMMDHHMMSS, Locale.US);
local.set(sdf);
}
return sdf.parse(str);
}
public static String localFormat(Date date) throws Exception {
SimpleDateFormat sdf = local.get();
if (sdf == null) {
sdf = new SimpleDateFormat(YYYYMMDHHMMSS, Locale.US);
local.set(sdf);
}
return sdf.format(date);
}
/** * 使用 synchronized */
public static String syncFormat(Date date) throws ParseException {
synchronized (sdf) {
return sdf.format(date);
}
}
public static Date syncParse(String strDate) throws ParseException {
synchronized (sdf) {
return sdf.parse(strDate);
}
}
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static String formatDate2(LocalDateTime date) {
return formatter.format(date);
}
public static LocalDateTime parse2(String dateNow) {
return LocalDateTime.parse(dateNow, formatter);
}
}
public class DateFormatTest {
private static final Log log = LogFactory.getLog(DateFormatTest.class);
public static void main(String[] args) throws Exception {
multiThreadFormat();
multiThreadParse();
}
private static void multiThreadParse() throws Exception {
ExecutorService service = Executors.newFixedThreadPool(100);
String myDateStr = "2018-07-02 09:45:56";
for (int i = 0; i < 20; i++) {
service.execute(() -> {
for (int j = 0; j < 10; j++) {
try {
Date parsedDate = DateUtils.parse(myDateStr);
System.out.println("parsedDate = " + parsedDate);
} catch (Exception e) {
System.out.println("Error parse,-------------- ," + e);
}
}
});
}
log.info("格式化 parse 结束,myDateStr = " + myDateStr);
// 等待上述的线程执行完
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);
}
private static void multiThreadFormat() throws Exception {
ExecutorService service = Executors.newFixedThreadPool(100);
String myDateStr = "2018-07-02 09:45:56";
Date myDate = DateUtils.safeParseDate(myDateStr, null);
for (int i = 0; i < 210; i++) {
service.execute(() -> {
for (int j = 0; j < 20; j++) {
try {
String formatedDate = DateUtils.format(myDate);
if (!myDateStr.equals(formatedDate)) {
log.info("格式化失败了,formatedDate = " + formatedDate);
}
} catch (Exception e) {
System.out.println("Error,-------------- ," + e);
}
}
});
}
log.info("格式化 format 结束,myDateStr = " + myDateStr);
// 等待上述的线程执行完
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);
}
}
问题场景复现
@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);
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;
}
Date formats are not synchronized. It is recommended to create separate format instances for each thread.
If multiple threads access a format concurrently,
it must be synchronized externally.
意思就是日期格式化方法不同步,故建议为每个线程创建私有的实例。如果多个线程同时访问一种格式,则必须在外部为该格式加锁。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
LocalDate date = LocalDate.parse("2017 06 17", formatter);
System.out.println(formatter.format(date));
下面是《阿里巴巴开发手册》给我们的解决方案,对之前的代码进行改造:
public class SimpleDateFormatTest {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static String formatDate2(LocalDateTime date) {
return formatter.format(date);
}
public static LocalDateTime parse2(String dateNow) {
return LocalDateTime.parse(dateNow, formatter);
}
public static void main(String[] args) throws InterruptedException, ParseException {
ExecutorService service = Executors.newFixedThreadPool(100);
// 20个线程
for (int i = 0; i < 20; i++) {
service.execute(() -> {
for (int j = 0; j < 10; j++) {
try {
System.out.println(parse2(formatDate2(LocalDateTime.now())));
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
// 等待上述的线程执行完
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);
}
}
This class is immutable and thread-safe.
标签:mtk btv SOS i++ 不必要 ann 控制 leo otf
原文地址:https://www.cnblogs.com/east7/p/11256970.html