合理使用SimpleDateFormat
2015-06-29 22:16
507 查看
1.简单使用
可以得到如下的运行结果:
2.性能消耗
创建SimpleDateFormat是非常消耗性能的。
运行得到如下结果:
如上所示,代码中循环了10000次的反复调用,最后的时间消耗还是比较明显的。
可能你会觉得创建对象本身就会消耗性能,我先开始也是有这个疑问,看下面这段代码也许会比较直观。
这里的SomeObj只是一个比较的对象而已,不用去管里面是怎么写的。
比较这两段代码可知:
SimpleDateFormat的创建是很消耗性能的。
解决办法:
如上代码段所示,使用单例模式的确会提升性能,但这样做还是不够的。
3.安全性
SimepleDateFormat是非线程安全的。具体解释我不敢肯定。应该是在调用parse、format的时候会使用到一个Calendar对象。每次使用的时候,calendar会先后调用clean、getTime方法。这样如果多线程公用同一个calendar是会出问题的。(具体源代码日后再分析补充,如果描述不正确还请指出)。
具体的效果我们看下代码。
运行得到如下结果:
4.最终解决办法
public class SimpleUse { public static void main(String[] args) throws ParseException { //创建SimpleDateFormat对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //常见用法一:格式化日期为想要的字符串 String dateStr = sdf.format(new Date(System.currentTimeMillis())); System.out.println(dateStr); //常见用法二:解析字符串为日期 Date date = sdf.parse("2015-06-29 22:12:13"); System.out.println(date); } }
可以得到如下的运行结果:
<span style="font-size:14px;">2015-06-29 22:12:57 Mon Jun 29 22:12:13 CST 2015</span>
2.性能消耗
创建SimpleDateFormat是非常消耗性能的。
public class Problem1 { public static void main(String[] args) throws ParseException { String dateStr = "2015-06-29 12:22:22"; String pattern = "yyyy-MM-dd HH:mm:ss"; test1(dateStr,pattern); test2(dateStr,pattern); } public static void test1(String dateStr,String pattern) throws ParseException { long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { SimpleDateFormat sdf = new SimpleDateFormat(pattern); sdf.parse(dateStr); } long end = System.currentTimeMillis(); System.out.println("cost1=" + (end - start)); } public static void test2(String dateStr,String pattern) throws ParseException { Map<String, SimpleDateFormat> map = new HashMap<String, SimpleDateFormat>(); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { if (!map.containsKey(pattern)) { map.put(pattern, new SimpleDateFormat(pattern)); } SimpleDateFormat sdf = map.get(pattern); sdf.parse(dateStr); } long end = System.currentTimeMillis(); System.out.println("cost2=" + (end - start)); } }
运行得到如下结果:
cost1=640 cost2=62
如上所示,代码中循环了10000次的反复调用,最后的时间消耗还是比较明显的。
可能你会觉得创建对象本身就会消耗性能,我先开始也是有这个疑问,看下面这段代码也许会比较直观。
public class Problem2 { public static void main(String[] args) throws ParseException { String dateStr = "2015-06-29 12:22:22"; String pattern = "yyyy-MM-dd HH:mm:ss"; test1(dateStr, pattern); test2(dateStr, pattern); } public static void test1(String dateStr, String pattern) throws ParseException { long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { SomeObj sdf = new SomeObj(pattern); sdf.parse(dateStr); } long end = System.currentTimeMillis(); System.out.println("cost1=" + (end - start)); } public static void test2(String dateStr, String pattern) throws ParseException { Map<String, SomeObj> map = new HashMap<String, SomeObj>(); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { if (!map.containsKey(pattern)) { map.put(pattern, new SomeObj(pattern)); } SomeObj sdf = map.get(pattern); sdf.parse(dateStr); } long end = System.currentTimeMillis(); System.out.println("cost2=" + (end - start)); } }运行得到如下结果:
cost1=2 cost2=10
这里的SomeObj只是一个比较的对象而已,不用去管里面是怎么写的。
比较这两段代码可知:
SimpleDateFormat的创建是很消耗性能的。
解决办法:
private static Map<String, SimpleDateFormat> map = new HashMap<String, SimpleDateFormat>(); public static SimpleDateFormat getInstance(String pattern) { if (!map.containsKey(pattern)) { map.put(pattern, new SimpleDateFormat(pattern)); } return map.get(pattern); }
如上代码段所示,使用单例模式的确会提升性能,但这样做还是不够的。
3.安全性
SimepleDateFormat是非线程安全的。具体解释我不敢肯定。应该是在调用parse、format的时候会使用到一个Calendar对象。每次使用的时候,calendar会先后调用clean、getTime方法。这样如果多线程公用同一个calendar是会出问题的。(具体源代码日后再分析补充,如果描述不正确还请指出)。
具体的效果我们看下代码。
public class MultipleThreadDemo implements Runnable { String pattern; public MultipleThreadDemo(String pattern) { this.pattern = pattern; } @Override public void run() { SimpleDateFormat sdf = getInstance(); int count = 10; while (count-- > 0) { try { sdf.parse(pattern); sdf.format(new Date(System.currentTimeMillis())); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { MultipleThreadDemo d1 = new MultipleThreadDemo("2015-06-21"); MultipleThreadDemo d2 = new MultipleThreadDemo("2015-06-22"); new Thread(d1).start(); new Thread(d2).start(); } private static SimpleDateFormat sdf_ = new SimpleDateFormat("yyyy-MM-dd"); public static SimpleDateFormat getInstance() { return sdf_; } }
运行得到如下结果:
java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1110) at java.lang.Double.parseDouble(Double.java:540) at java.text.DigitList.getDouble(DigitList.java:168) at java.text.DecimalFormat.parse(DecimalFormat.java:1321) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455) at java.text.DateFormat.parse(DateFormat.java:355) at com.cp.demo.SimpleDateFormatDemo.MultipleThreadDemo.run(MultipleThreadDemo.java:20) at java.lang.Thread.run(Thread.java:745)这样的话,多线程共同使用同一个SimpleDateFormat是不行的。
4.最终解决办法
public class SolveDemo implements Runnable { String pattern; public SolveDemo(String pattern) { this.pattern = pattern; } @Override public void run() { SimpleDateFormat sdf = getInstance(); int count = 100; while(count-->0){ try { sdf.parse(pattern); sdf.format(new Date(System.currentTimeMillis())); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { SolveDemo d1 = new SolveDemo("2015-06-21"); SolveDemo d2 = new SolveDemo("2015-06-22"); new Thread(d1).start(); new Thread(d2).start(); } private static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>(); public static SimpleDateFormat getInstance() { SimpleDateFormat sdf = SolveDemo.threadLocal.get(); if (sdf != null) { return sdf; } SimpleDateFormat sdf_ = new SimpleDateFormat("yyyy-MM-dd"); System.out.println(Thread.currentThread().getName()+":创建一个sdf"); SolveDemo.threadLocal.set(sdf_); return sdf_; } }运行得到如下结果:
Thread-0:创建一个sdf Thread-1:创建一个sdf这里使用了ThreadLocal为每个线程创建了单独的一个SimpleDateFormat实例,有效地防止了多个线程之间的干扰。
相关文章推荐
- Python3写爬虫(四)多线程实现数据爬取
- 选定虚拟主机 性能凸显优势
- 修改一行代码提升 Postgres 性能 100 倍
- C#实现多线程的同步方法实例分析
- 推荐Sql server一些常见性能问题的解决方法
- Linux系统 改善FTP服务器的安全性
- SQL Server误区30日谈 第9天 数据库文件收缩不会影响性能
- 和表值函数连接引发的性能问题分析
- SQLServer 2000 升级到 SQLServer 2008 性能之需要注意的地方之一
- C#简单多线程同步和优先权用法实例
- 数据库性能优化三:程序操作优化提升性能
- C#多线程学习之(四)使用线程池进行多线程的自动管理
- C#多线程编程中的锁系统(三)
- VBS中的字符串连接的性能问题
- C#多线程学习之(六)互斥对象用法实例
- 基于一个应用程序多线程误用的分析详解
- C#多线程学习之(三)生产者和消费者用法分析
- C#多线程学习之(一)多线程的相关概念分析
- C#多线程之Thread中Thread.IsAlive属性用法分析
- C#控制台下测试多线程的方法