在我们的代码的里面经常有这样的例子,为了格式化日期(如:2011-02-17), 就需要一个SimpleDateFormat类,同时,为了让整个系统共享这个格式化类,我们把这个格式化类写到一个公共的Util类里面,代码如下:
Util 类:
package com.maneco.art;
import java.text.SimpleDateFormat;
public class Util {
public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
}
Util类的使用者:
package com.maneco.art;
import java.text.ParseException;
public class MultiThread implements Runnable {
public static void main(String[] args) {
new Thread(new MultiThread()).start();
new Thread(new MultiThread()).start();
new Thread(new MultiThread()).start();
new Thread(new MultiThread()).start();
}
@Override
public void run() {
try {
for (int i = 0; i < 10000; i++) {
System.out.print(Util.sdf.parse("2000-01-05"));
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
如上面的代码,就会产生下面的异常:
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Long.parseLong(Unknown Source)
at java.lang.Long.parseLong(Unknown Source)
at java.text.DigitList.getLong(Unknown Source)
at java.text.DecimalFormat.parse(Unknown Source)
at java.text.SimpleDateFormat.subParse(Unknown Source)
at java.text.SimpleDateFormat.parse(Unknown Source)
at java.text.DateFormat.parse(Unknown Source)
at com.maneco.art.MultiThread.run(MultiThread.java:18)
at java.lang.Thread.run(Unknown Source)
原因在于:
如果是单线程,使用这个Util类是没有问题的;
如果是多线程的话,就会产生并发访问同一个实例化的SimpleDateFormat类。
JDK API中声明DateFormat类和SimpleDateFormat类都不是线程同步的,推荐对于每个线程创建一个实例。如果多线程访问的话,自己实现多线程同步;
1: 最简单的方法是在每次使用的时候,new一个新的DateFormat;效率稍许损失,不能达到系统共享同一个格式化类。最简单的编程模型。推荐。
2: 增加线程同步访问: 但是多线程的效率将损失,并且容易导致死锁。
private static final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
public static synchronized Date formatStr(String str) throws ParseException {
return Util.df.parse(str);
}
下面这种线程同步是没有意义的,因为仅仅拿到reference时是线程同步的,而不是使用时同步的。
private static final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
public static synchronized DateFormat getDateFomrater() {
return Util.df;
}
3: 如果对性能要求严格,可以封装一个类,在同步的代码里面对于每个线程根据线程Id去返回对应的实例类,
效率稍微损失,不会导致死锁,系统的格式化聚集在一个访问点:
private static final Map<Long, DateFormat> DateFormaterMap = new HashMap<Long, DateFormat>();
// return date formater by thread Id
public static DateFormat getDateFormaterByThread() {
Long tId = Thread.currentThread().getId();
if (Util.DateFormaterMap.containsKey(tId)) {
return Util.DateFormaterMap.get(tId);
} else {
// another strategy: use SimpleDateFormat's clone method with a default one
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Util.DateFormaterMap.put(tId, sdf);
return sdf;
}
}
建议在写单元测试的时候,增加一项多线程测试。
分享到:
相关推荐
javaweb毕业设计-Java多线程与线程安全实践-基于Http协议的断点续传(可做课程设计).rarjavaweb毕业设计-Java多线程与线程安全实践-基于Http协议的断点续传(可做课程设计).rarjavaweb毕业设计-Java多线程与线程安全...
vc++ 多线程教程---线程通信--利用事件对象,线程同步--使用信号量,线程同步--使用互斥量,线程同步--使用临界区
Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程...
Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多...
Java多线程与线程安全实践-基于Http协议的断点续传.zip Java多线程与线程安全实践-基于Http协议的断点续传.zip Java多线程与线程安全实践-基于Http协议的断点续传.zip Java多线程与线程安全实践-基于Http协议的断点...
Java多线程--线程安全问题练习题
JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多...
Java多线程与线程安全实践-基于Http协议的断点续传.rarJava多线程与线程安全实践-基于Http协议的断点续传.rarJava多线程与线程安全实践-基于Http协议的断点续传.rarJava多线程与线程安全实践-基于Http协议的断点续传...
线程安全2--下面我们再给出一个线程不安全的例子1---马克-to-win java视频
人工智能-项目实践-多线程-多线程爬虫--抓取淘宝商品详情页URL 本项目是一个Java编写的多线程爬虫系统。此系统与我之前开发的ip-proxy-pools-regularly结合使用,共抓取了淘宝近3000个页面,从中解析到了近9万的...
Java多线程--线程的安全问题与线程的同步机制介绍
人工智能-项目实践-多线程-多线程与高并发 多线程与高并发
人工智能-项目实践-多线程-一个多线程多进程的下载DEMO 人工智能-项目实践-多线程-一个多线程多进程的下载DEMO
golang-set - Go的线程安全的和非线程安全的高性能集
多线程相关知识源码-----多线程案例源码
Java多线程--同步机制解决线程安全问题方式二:同步方法
人工智能-项目实践-多线程-tonado的multi-thread 多线程封装 Quick Start 1.在“biz”目录中创建一个py文件,文件名任意但最好不要跟第三方库冲突 2.使用 "Router.route" 装饰器注册函数到路由表中,仿造示例即可 ...