项目终于接近尾声,下周上线,没有太多事情,为了保证代码质量,所以现在更多的事情是codereview,顺便也补充下能量,首先分享一个压力测试下的case吧,
simpleDateFormat作为全局变量时,存在线程不安全问题,容易引起值覆盖问题,当然在使用全局变量,高并发环境下又没使用线程安全的情况下,都会导致这个问题,虽然源代码很明白可以觉察这个问题,但还是贴上代码更有说服力:
package reference.unsafe;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Format {
private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String formatYmdHms(Date date){
try {
return dateFormat.format(date);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static String formatYmdHms1(Date date){
try {
return dateFormat.format(date);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static void main(String[] args) {
System.out.println(new Date());
}
}
-----------------------------------华丽分割------------------------------------------
package reference.unsafe;
import java.util.Calendar;
import java.util.Date;
public class Test {
public static void main(String[] args) {
Test tt = new Test();
for (int i = 0; i < 50; i++) {
tt.new formatD().start();
tt.new formatM().start();
}
}
class formatD extends Thread{
public formatD(){
super.setName("QQ");
}
public void run(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程名称【"+Thread.currentThread().getName()+"】,当前时间:【"+new Date()+"】,格式后:【"+Format.formatYmdHms(new Date())+"】");
}
}
class formatM extends Thread{
public formatM(){
super.setName("PP");
}
public void run(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.HOUR_OF_DAY, 2);
System.out.println("线程名称【"+Thread.currentThread().getName()+"】,当前时间:【"+new Date()+"】,格式后:【"+Format.formatYmdHms1(calendar.getTime())+"】");
}
}
}
再分析下jdk下simpleDateFormat源码
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);
很容易看出多个线程都进入到format方法,更改了calendar,问题就发生了,如何解决这个问题呢?这里给出两种
解决方案吧,首先肯定是局部变量如:return new SimpleDateFormat("yyyy.MM.dd").format(new Date());
也可以使用副本:
private static ThreadLocal ymdFormatThreadLocal = new ThreadLocal() {
protected Object initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
这里再贴上一遍参考文章,他的系列代码之丑文章,不错,作为java开发人员可以参考,引以为戒
http://www.infoq.com/cn/news/2012/06/ugly-code-12
最后为了给自己补充能量,贴上两个开源代码svn,有兴趣的同学可以研究下
http://svn.apache.org/repos/asf/tomcat/tc7.0.x/trunk
https://github.com/taobao/tedis