SimpleDateFormat线程安全问题解决

使用SimpleDateFormat在多线程下处理日期但得出的结果却是错误的,这是因为SimpleDateFormat方法是非线程安全的。

示例代码:

class MyThread extends Thread {
    private SimpleDateFormat sdf;
    private String dateString;
    public MyThread(SimpleDateFormat sdf, String dateString) {
        this.sdf = sdf;
        this.dateString = dateString;
    }
 
    @Override
    public void run() {
        try {
            Date date = sdf.parse(dateString);
            String dateStr = sdf.format(date);
            if(!dateStr.equals(dateString)) {
                System.out.println("ThreadName=" + this.getName() + "报错了,日期字符串:" + dateString + ",转换成的日期字符串:" + dateStr);
            } else {
                System.out.println("ThreadName=" + this.getName() + "成功,日期字符串:" + dateString);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
public class Test {
 
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String[] dateString = {"2017-11-05","2017-11-06","2017-11-07","2017-11-08","2017-11-09","2017-11-10","2017-11-11","2017-11-12","2017-11-13","2017-11-14"};
        Thread[] threads = new Thread[10];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new MyThread(sdf, dateString[i]);
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
    }
}


输出结果:
ThreadName=Thread-5成功,日期字符串:2017-11-10
ThreadName=Thread-0报错了,日期字符串:2017-11-05,转换成的日期字符串:2017-11-10
ThreadName=Thread-1成功,日期字符串:2017-11-06
ThreadName=Thread-4报错了,日期字符串:2017-11-09,转换成的日期字符串:2017-11-10
ThreadName=Thread-9成功,日期字符串:2017-11-14
ThreadName=Thread-3成功,日期字符串:2017-11-08
ThreadName=Thread-8成功,日期字符串:2017-11-13
ThreadName=Thread-7成功,日期字符串:2017-11-12
ThreadName=Thread-6报错了,日期字符串:2017-11-11,转换成的日期字符串:0007-11-11
ThreadName=Thread-2报错了,日期字符串:2017-11-07,转换成的日期字符串:0007-11-11


通过输出结果可以看出不是所有线程都成功了,有些线程转换的字符串很奇怪,这都是因为多线程导致的,多线程可能会出现很多我们意想不到的结果,每次运行以上代码都可能会得到不一样的结果。

解决方法一:

在使用SimpleDateFormat对象时,每次都新创建一个。

示例代码:

class MyThread1 extends Thread {
 
    private String dateString;
    public MyThread1(String dateString) {
        this.dateString = dateString;
    }
 
    @Override
    public void run() {
        try {
            Date date = DateTools.parse("yyyy-MM-dd", dateString);
            String dateStr = DateTools.format("yyyy-MM-dd", date);
            if(!dateStr.equals(dateString)) {
                System.out.println("ThreadName=" + this.getName() + "报错了,日期字符串:" + dateString + ",转换成的日期字符串:" + dateStr);
            } else {
                System.out.println("ThreadName=" + this.getName() + "成功,日期字符串:" + dateString);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
class DateTools {
    public static String format(String format, Date date) {
        return new SimpleDateFormat(format).format(date);
    }
    public static Date parse(String format, String dateStr) throws ParseException {
        return new SimpleDateFormat(format).parse(dateStr);
    }
}
 
public class Test1 {
    public static void main(String[] args) {
        String[] dateString = {"2017-11-05","2017-11-06","2017-11-07","2017-11-08","2017-11-09","2017-11-10","2017-11-11","2017-11-12","2017-11-13","2017-11-14"};
        Thread[] threads = new Thread[10];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new MyThread1(dateString[i]);
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
    }
}

输出结果:
ThreadName=Thread-7成功,日期字符串:2017-11-12
ThreadName=Thread-4成功,日期字符串:2017-11-09
ThreadName=Thread-6成功,日期字符串:2017-11-11
ThreadName=Thread-5成功,日期字符串:2017-11-10
ThreadName=Thread-1成功,日期字符串:2017-11-06
ThreadName=Thread-2成功,日期字符串:2017-11-07
ThreadName=Thread-3成功,日期字符串:2017-11-08
ThreadName=Thread-9成功,日期字符串:2017-11-14
ThreadName=Thread-8成功,日期字符串:2017-11-13
ThreadName=Thread-0成功,日期字符串:2017-11-05

通过输出结果可以看出,多线程日期转换的过程中没有出现异常,通过避免多线程同时使用一个SimpleDateFormat对象而带来的问题,可以为每个线程都创建一个新的SimpleDateFormat对象,所以就不会出现线程安全的问题了。

解决方法二:

使用ThreadLocal类,ThreadLocal类能使线程绑定到指定的对象上。

示例代码:

class MyThread2 extends Thread {
    private String dateString;
    public MyThread2(String dateString) {
        this.dateString = dateString;
    }
 
    @Override
    public void run() {
        try {
            Date date = DateTools2.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);
            String dateStr = DateTools2.getSimpleDateFormat("yyyy-MM-dd").format(date);
            if(!dateStr.equals(dateString)) {
                System.out.println("ThreadName=" + this.getName() + "报错了,日期字符串:" + dateString + ",转换成的日期字符串:" + dateStr);
            } else {
                System.out.println("ThreadName=" + this.getName() + "成功,日期字符串:" + dateString);
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
class DateTools2 {
    private static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<>();
    public static SimpleDateFormat getSimpleDateFormat(String format) {
        SimpleDateFormat sdf = null;
        sdf = threadLocal.get();
        if (sdf == null) {
            sdf = new SimpleDateFormat(format);
            threadLocal.set(sdf);
        }
        return sdf;
    }
}
public class Test2 {
    public static void main(String[] args) {
        String[] dateString = {"2017-11-05","2017-11-06","2017-11-07","2017-11-08","2017-11-09","2017-11-10","2017-11-11","2017-11-12","2017-11-13","2017-11-14"};
        Thread[] threads = new Thread[10];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new MyThread2(dateString[i]);
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
    }
}

运行结果:
ThreadName=Thread-1成功,日期字符串:2017-11-06
ThreadName=Thread-6成功,日期字符串:2017-11-11
ThreadName=Thread-4成功,日期字符串:2017-11-09
ThreadName=Thread-8成功,日期字符串:2017-11-13
ThreadName=Thread-7成功,日期字符串:2017-11-12
ThreadName=Thread-5成功,日期字符串:2017-11-10
ThreadName=Thread-0成功,日期字符串:2017-11-05
ThreadName=Thread-9成功,日期字符串:2017-11-14
ThreadName=Thread-3成功,日期字符串:2017-11-08
ThreadName=Thread-2成功,日期字符串:2017-11-07

通过结果可以看出,解决了SimpleDateFormat多线程访问异常的问题。

总结:

为什么SimpleDateFormat类多线程访问时会出现异常,原因是因为SimpleDateFormat中的方法不是线程安全的,多线程访问会出现意想不到的结果。解决的思路就是,避免多线程使用同一个SimpleDateFormat对象。

原文:https://blog.csdn.net/u014740338/article/details/78544821 
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值