疑惑,测试SimpleDateFormat并发的代码执行结果很奇怪。。。

前几天工作中,遇到一个并发环境下有人写了SimpleDateFormat的场景,印象中这个是不能支持多线程的,应该使用ThreadLocal作为每个线程局部变量使用,今天有空,试了下SimpleDateFormat多线程使用,代码如下:

/**
 * TestDateFormat.java
 * zhm.test.dateFormat
 * 2018年5月2日下午9:02:07
 *
 */
package zhm.test.dateFormat;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

/**
 * @author zhuheming TestDateFormat 2018年5月2日下午9:02:07
 */
public class TestDateFormat {

    public static TestDateFormat tdf = null;

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    public static void main(String[] args) {
        tdf = new TestDateFormat();
        for (int i = 1; i <= 9; i++) {

            Thread th = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        Random r = new Random();
                        int k = r.nextInt(100);

                        int randomSwitch = k % 3;

                        Calendar c = Calendar.getInstance();
                        c.add(Calendar.DATE, k);
                        try {
                            Thread.sleep(100);
                            switch (randomSwitch) {
                            case 0:
                                String s1 = c.get(Calendar.YEAR) + "-"
                                        + TestDateFormat.formatNumber((c.get(Calendar.MONTH) + 1)) + "-"
                                        + TestDateFormat.formatNumber((c.get(Calendar.DAY_OF_MONTH)));
                                Date date1 = tdf.printDateFormat(s1);
                                String d1 = new Timestamp(date1.getTime()).toString();
                                d1 = d1.substring(0,d1.indexOf(" "));
                                if(!s1.equals(d1)){
                                    System.out.println(s1+"     "+d1);
                                }
                                break;
                            case 1:
                                String s2 = c.get(Calendar.YEAR) + "-"
                                        + TestDateFormat.formatNumber((c.get(Calendar.MONTH) + 1)) + "-"
                                        + TestDateFormat.formatNumber((c.get(Calendar.DAY_OF_MONTH)));
                                Date date2 = TestDateFormat.printStaticDateFormat(s2);
                                String d2 = new Timestamp(date2.getTime()).toString();
                                d2 = d2.substring(0,d2.indexOf(" "));
                                if(!s2.equals(d2)){
                                    System.out.println(s2+"     "+d2);
                                }
                                break;
                            case 2:
                                String s = c.get(Calendar.YEAR) + "-"
                                        + TestDateFormat.formatNumber((c.get(Calendar.MONTH) + 1)) + "-"
                                        + TestDateFormat.formatNumber((c.get(Calendar.DAY_OF_MONTH)));
                                Date date3 = tdf.printReferenceDateFormat(s);
                                String d3 = new Timestamp(date3.getTime()).toString();
                                d3 = d3.substring(0,d3.indexOf(" "));
                                if(!s.equals(d3)){
                                    System.out.println(s+"     "+d3);
                                }
                                break;
                            default:
                                return;

                            }
                        } catch (Exception e) {

                        }
                    }
                }
            });
            th.start();
            try {
                th.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    public Date printReferenceDateFormat(String str) {
        System.out.println("get the ReferenceDateFormat:" + sdf);
        try {
            return sdf.parse(str);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

    public static Date printStaticDateFormat(String str) {
        SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println("get static method the SimpleDateFormat:" + df1);
        try {
            return df1.parse(str);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

    public Date printDateFormat(String str) {
        SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd");

        try {

            System.out.println("get the SimpleDateFormat:" + df2);
            return df2.parse(str);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

    private static String formatNumber(int n) {
        String s = "0" + n;
        return s.substring(s.length() - 2);
    }
}



按照设想,应该是sdf打印出的对象是同一个,后面两个打印出的对象因为每次需要新建对象,打印出来的都不相同才对。

但是结果如下:
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get static method the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200
get the SimpleDateFormat:java.text.SimpleDateFormat@f67a0200
get the ReferenceDateFormat:java.text.SimpleDateFormat@f67a0200

对象居然是同一个,这就很奇怪了,谁知道原因呢?

看了下SimpleDateFormat源码,里面根据pattern从static的concurrentHashMap中取对应的信息,对于不同的SimpleDateFormat对象,只要定义的格式相同,pattern对象是同一个。

后来换了种方式测试,直接粗暴的写五个进程跑,证明确实会出现并发问题:
2018-12-25 2203-01-24
2498-10-10 2203-01-24
2018-12-25 0001-10-10
2998-01-02 3004-12-01
1698-09-22 3004-12-01
且只有共享的static会有这个问题,去掉共享的static,那么在方法内调用的就不存在并发问题。


/**
 * TestDateFormat.java
 * zhm.test.dateFormat
 * 2018年5月2日下午9:02:07
 *
 */
package zhm.test.dateFormat;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

/**
 * @author zhuheming TestDateFormat 2018年5月2日下午9:02:07
 */
public class TestDateFormat {

    public static TestDateFormat tdf = null;

    //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    public static void main(String[] args) {
        tdf = new TestDateFormat();


            Thread th1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        Random r = new Random();
                        int k = r.nextInt(100);

                        int randomSwitch = k % 3;

                        //Calendar c = Calendar.getInstance();
                        //c.add(Calendar.DATE, k);
                        try {
                            Thread.sleep(100);
                            switch (randomSwitch) {
                            case 0:
                                String s1 = "2018-12-25";
                                String d1 = tdf.printDateFormat(s1);
                                //String d1 = new Timestamp(date1.getTime()).toString();
                                //d1 = d1.substring(0,d1.indexOf(" "));
                                if(!s1.equals(d1)){
                                    System.out.println(s1+"     "+d1);
                                }
                                break;
                            case 1:
                                String s2 = "2018-12-25";
                                String d2 = TestDateFormat.printStaticDateFormat(s2);
                                //String d2 = new Timestamp(date2.getTime()).toString();
                                //d2 = d2.substring(0,d2.indexOf(" "));
                                if(!s2.equals(d2)){
                                    System.out.println(s2+"     "+d2);
                                }
                                break;
                            case 2:
                                String s ="2018-12-25";
                                String d3 = tdf.printReferenceDateFormat(s);
                                //String d3 = new Timestamp(date3.getTime()).toString();
                                //d3 = d3.substring(0,d3.indexOf(" "));
                                if(!s.equals(d3)){
                                    System.out.println(s+"     "+d3);
                                }
                                break;
                            default:
                                return;

                            }
                        } catch (Exception e) {

                        }
                    }
                }
            });

    Thread th2 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                Random r = new Random();
                int k = r.nextInt(3);
                int randomSwitch = k % 3;

                //Calendar c = Calendar.getInstance();
                //c.add(Calendar.DATE, k);
                try {
                    Thread.sleep(100);
                    switch (randomSwitch) {
                    case 0:
                        String s1 = "1998-11-12";
                        String d1 = tdf.printDateFormat(s1);
                        //String d1 = new Timestamp(date1.getTime()).toString();
                        //d1 = d1.substring(0,d1.indexOf(" "));
                         if(!s1.equals(d1)){
                            System.out.println(s1+"     "+d1);
                         }
                        break;
                    case 1:
                        String s2 = "1998-11-12";
                        String d2 = TestDateFormat.printStaticDateFormat(s2);
                        //String d2 = new Timestamp(date2.getTime()).toString();
                        //d2 = d2.substring(0,d2.indexOf(" "));
                        if(!s2.equals(d2)){
                            System.out.println(s2+"     "+d2);
                        }
                        break;
                    case 2:
                        String s = "1998-11-12";
                        String d3 = tdf.printReferenceDateFormat(s);
                        //String d3 = new Timestamp(date3.getTime()).toString();
                        //d3 = d3.substring(0,d3.indexOf(" "));
                        if(!s.equals(d3)){
                            System.out.println(s+"     "+d3);
                        }
                        break;
                    default:
                        return;

                    }
                } catch (Exception e) {

                }
            }
        }
    });

    Thread th3 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                Random r = new Random();
                int k = r.nextInt(3);
                int randomSwitch = k % 3;

                //Calendar c = Calendar.getInstance();
                //c.add(Calendar.DATE, k);
                try {
                    Thread.sleep(100);
                    switch (randomSwitch) {
                    case 0:
                        String s1 = "1698-09-22";
                        String d1 = tdf.printDateFormat(s1);
                        //String d1 = new Timestamp(date1.getTime()).toString();
                        //d1 = d1.substring(0,d1.indexOf(" "));
                         if(!s1.equals(d1)){
                            System.out.println(s1+"     "+d1);
                         }
                        break;
                    case 1:
                        String s2 = "1698-09-22";
                        String d2 = TestDateFormat.printStaticDateFormat(s2);
                        //String d2 = new Timestamp(date2.getTime()).toString();
                        //d2 = d2.substring(0,d2.indexOf(" "));
                        if(!s2.equals(d2)){
                            System.out.println(s2+"     "+d2);
                        }
                        break;
                    case 2:
                        String s = "1698-09-22";
                        String d3 = tdf.printReferenceDateFormat(s);
                        //String d3 = new Timestamp(date3.getTime()).toString();
                        //d3 = d3.substring(0,d3.indexOf(" "));
                        if(!s.equals(d3)){
                            System.out.println(s+"     "+d3);
                        }
                        break;
                    default:
                        return;

                    }
                } catch (Exception e) {

                }
            }
        }
    });

    Thread th4 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                Random r = new Random();
                int k = r.nextInt(3);
                int randomSwitch = k % 3;

                //Calendar c = Calendar.getInstance();
                //c.add(Calendar.DATE, k);
                try {
                    Thread.sleep(100);
                    switch (randomSwitch) {
                    case 0:
                        String s1 = "2498-10-10";
                        String d1 = tdf.printDateFormat(s1);
                        //String d1 = new Timestamp(date1.getTime()).toString();
                        //d1 = d1.substring(0,d1.indexOf(" "));
                         if(!s1.equals(d1)){
                            System.out.println(s1+"     "+d1);
                         }
                        break;
                    case 1:
                        String s2 = "2498-10-10";
                        String d2 = TestDateFormat.printStaticDateFormat(s2);
                        //String d2 = new Timestamp(date2.getTime()).toString();
                        //d2 = d2.substring(0,d2.indexOf(" "));
                        if(!s2.equals(d2)){
                            System.out.println(s2+"     "+d2);
                        }
                        break;
                    case 2:
                        String s = "2498-10-10";
                        String d3 = tdf.printReferenceDateFormat(s);
                        //String d3 = new Timestamp(date3.getTime()).toString();
                        //d3 = d3.substring(0,d3.indexOf(" "));
                        if(!s.equals(d3)){
                            System.out.println(s+"     "+d3);
                        }
                        break;
                    default:
                        return;

                    }
                } catch (Exception e) {

                }
            }
        }
    });

    Thread th5 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                Random r = new Random();
                int k = r.nextInt(3);
                int randomSwitch = k % 3;

                //Calendar c = Calendar.getInstance();
                //c.add(Calendar.DATE, k);
                try {
                    Thread.sleep(100);
                    switch (randomSwitch) {
                    case 0:
                        String s1 = "2998-01-02";
                        String d1 = tdf.printDateFormat(s1);
                        //String d1 = new Timestamp(date1.getTime()).toString();
                        //d1 = d1.substring(0,d1.indexOf(" "));
                         if(!s1.equals(d1)){
                            System.out.println(s1+"     "+d1);
                         }
                        break;
                    case 1:
                        String s2 = "2998-01-02";
                        String d2 = TestDateFormat.printStaticDateFormat(s2);
                        //String d2 = new Timestamp(date2.getTime()).toString();
                        //d2 = d2.substring(0,d2.indexOf(" "));
                        if(!s2.equals(d2)){
                            System.out.println(s2+"     "+d2);
                        }
                        break;
                    case 2:
                        String s = "2998-01-02";
                        String d3 = tdf.printReferenceDateFormat(s);
                        //String d3 = new Timestamp(date3.getTime()).toString();
                        //d3 = d3.substring(0,d3.indexOf(" "));
                        if(!s.equals(d3)){
                            System.out.println(s+"     "+d3);
                        }
                        break;
                    default:
                        return;

                    }
                } catch (Exception e) {

                }
            }
        }
    });
    th1.start();
    th2.start();
    th3.start();
    th4.start();
    th5.start();
    try {
        th1.join();
        th2.join();
        th3.join();
        th4.join();
        th5.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}


    public String printReferenceDateFormat(String str) {
        //Date dt= sdf.parse(str);
        //return sdf.format(dt);
        return str;
    }

    public static String printStaticDateFormat(String str) {
        SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
        //System.out.println("get static method the SimpleDateFormat:" + df1);
        try {
            Thread.sleep(100);
            Date dt=df1.parse(str);
            str=df1.format(dt);
            //df1.getCalendar().clear();
            return str;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

    public String printDateFormat(String str) {
        SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd");

        try {
            Thread.sleep(100);
            Date dt=df2.parse(str);
            str=df2.format(dt);
            //df2.getCalendar().clear();
            //System.out.println("get the SimpleDateFormat:" + df2);
            return str;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

}

那么只有最后一个问题了,为什么看起来是同一个对象呢:

大家都知道system.out.prinl(object)其实是打印的String.valueof的对象值;valueof是什么呢?
public static String valueOf(Object obj) {
return (obj == null) ? “null” : obj.toString();
}
就是obj的toString的值,那么obj的toString由Object类定义,各个子类自己重写,在Object中,定义如下:
public String toString() {
return getClass().getName() + “@” + Integer.toHexString(hashCode());
}

显然就是Object的hashCode的十六进制数值,那么在SimpleDateFormat中hashcode方法是如何呢?
public int hashCode()
{
return pattern.hashCode();
// just enough fields for a reasonable distribution
}
从这里可以看出,SimpleDateFormat没有返回自己的对象的地址等,而是返回了pattern的hashcode,前面已经说过,输入的格式相同,pattern是同一个,所以,此处SimpleDateFormat对象打印出来是同一个,但其实不是。

每次看源码,带着疑问看源代码,总是能让人收获很多,大家共勉。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值