在使用SimpleDateFormat的经常会有一些错误的用法,例如如下方式:
public class TestDateFormat{
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public void method1(){
sdf.format(new Date());
}
public void method2(){
sdf.format(new Date());
}
)
为了渐少new 的次数而把SimpleDateFormat做成成员或者静态成员,但这样的做法是隐含着错误的,是不安全
的。如下给出证明:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class TestDateFormat{
private SimpleDateFormat sdf ;
public static void main(String[] args) {
SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd");
Date date1 = new Date();
Date date2 = new Date(date1.getTime()+1000*60*60*24);
System.out.println(date1);
System.out.println(date2);
Thread thread1 = new Thread(new Thread1(sdf,date1));
thread1.start();
Thread thread2 = new Thread(new Thread2(sdf,date2));
thread2.start();
}
}
class Thread1 implements Runnable{
private SimpleDateFormat sdf;
private Date date;
public Thread1(SimpleDateFormat sdf,Date date){
this.sdf = sdf;
this.date = date;
}
public void run() {
for(;;){
String strDate = sdf.format(date);
if("2007-02-27".equals(strDate)){
System.err.println("Error: date1="+strDate);
System.exit(0);
}
}
}
}
class Thread2 implements Runnable{
private SimpleDateFormat sdf;
private Date date;
public Thread2(SimpleDateFormat sdf,Date date){
this.sdf = sdf;
this.date = date;
}
public void run() {
for(;;){
String strDate = sdf.format(date);
if("2007-02-26".equals(strDate)){
System.err.println("Error: date1="+strDate);
System.exit(0);
}
}
}
}
很快,基本几十次就会出现错误。错误原因:
因为SimpleDateFormat处理复杂,Jdk的实现中使用了成员变量来传递参数,这个就造成在多线程的时候
会出现错误。上边的程序证明了这个问题。
再看看SimpleDateFormat的Jdk 的Source,有这么一段注释,说明它不是线程安全的。
Date formats are not synchronized.
* It is recommended to create separate format instances for each thread.
* If multiple threads access a format concurrently, it must be synchronized
继续看看Sun自己的网站上。在sun的bug database中
Bug ID: 4228335 讲的就是这个问题。
SimpleDateFormat is not threadsafe (one more try)
其中有这么几段话值得关注:
1,
Aside from the obvious, there are two reasons why this fix should be made:
- The documentation for DateFormat states that a DateFormat object should be used
multiple times, implying that construction is expensive. Furthermore,
no mention is made of SimpleDateFormat's lack of thread-safety.
Since for most applications the date formats remain constant,
it is very easy to conclude that DateFormats should be application globals.
But SimpleDateFormat produces incorrect results when used in this way.
- Bug 4101500, a similar problem with NumberFormat, was fixed.
建议修改这个问题,而且NumberFormat已经修改,解决了这个问题。简单测试了一下NumberFormat确是不出错
2,
Use of a cloned Calendar object in format(), as suggested in JDC comments,
slows down the execution 30-50%. And it potentially affects footprint because
of cloned objects. Another approach would be to have a Calendar instance per
thread. However, this approach will cause problems at the API semantic level due
to the get/setCalendar methods.
这一段解释了为什么没修改这个问题,一个是保持API不变,另一个是因为Clone比new慢,会损失效率。
结论:每次使用它的时候现new,或者用一个同步函数把new好的包装起来使用吧。
分享到:
相关推荐
在Java中,将包含日期和时间的String转换为Date对象,可以使用`SimpleDateFormat`类进行解析。例如: ```java String strDate = "2022-01-01 12:00:00"; SimpleDateFormat formatter = new SimpleDateFormat(...
同步就是在方法返回类型后面加上synchronized。 c#中的委托,事件是不是委托? 答:委托就是将方法作为一个参数带入另一个方法叫做委托,事件是一种特殊的委托。 应用程序域? 答:应用程序域可以理解为一种轻量级的...
这意味着,在多线程环境下直接复用一个`SimpleDateFormat`实例可能会导致数据错误或异常。 **3.2 解决方案** 1. **每次 new 一个新的对象**:这是最简单但不是最高效的解决办法。 示例代码: ```java public ...
19. **转发与重定向**:转发是在服务器内部完成的,浏览器地址栏不会改变;重定向是客户端发起新的请求,浏览器地址栏显示新URL。 20. **HashMap与Hashtable**:HashMap是非线程安全的,允许null键值;Hashtable是...
- 局部内部类:在方法或块中定义的类,作用范围仅限于该方法或块。 - 匿名内部类:没有名字的内部类,常用于简化代码,尤其在实现接口时。 13. **实现序列化**: - 除了直接实现`Serializable`接口,还可以使用`...
- 在网页中引入JavaScript的方法。 - JavaScript的基本语法与使用方法。 #### 三、JavaEE框架 **SSH(Spring、Struts、Hibernate)** - **Spring** - IoC容器: 控制反转,管理对象的生命周期。 - AOP: 面向切...
在JSP中,使用`request.getParameter()`方法读取客户端请求参数;使用`pageContext.getRealPath("/")`获取JSP文件的真实路径。 **4. Cookie与Session** - **Cookie**:存储在客户端,用于记录用户信息。 - **...
9. **请求转发**:在Servlet中使用`RequestDispatcher.forward()`方法;在JSP中可以使用`<jsp:forward>`标签。 ### J2EE相关知识 1. **J2EE、J2SE、J2ME的区别**:J2EE面向企业级应用,包括EJB等高级特性;J2SE...
日期格式化通常使用SimpleDateFormat类完成。 #### 15. PreparedStatement与Statement的区别 `PreparedStatement`是`Statement`的子类,它预编译SQL语句,可以防止SQL注入攻击,并提高性能,尤其是当SQL语句重复...
- **日期格式化**: 使用`SimpleDateFormat`或`DateTimeFormatter`。 5. **数组和集合** - 数组是固定长度的数据结构,而集合是动态大小的数据结构,如`List`、`Set`和`Map`。 6. **文件和目录(I/O)操作** - *...
- **格式化日期**:使用SimpleDateFormat或DateTimeFormatter。 #### 5. 数组和集合 - **数组**:固定长度的数据结构,用于存储同类型的元素。 - **集合**:动态扩展的数据结构,如List、Set、Map等,用于存储不同...
转发发生在服务器端,保持原请求URL;重定向是客户端的新请求,浏览器地址栏会显示新URL。 8. **<select><option>的作用**: HTML中的用于创建下拉列表,定义下拉选项。 9. **Struts标记**: Struts是MVC框架,...
- 格式化日期:使用 `java.text.SimpleDateFormat` 或 `java.time.format.DateTimeFormatter`。 5. **数组和集合** - 数组是固定长度的数据结构,用于存储相同类型的元素。 - 集合框架包括 `List`、`Set` 和 `...
9. **请求转发**:在Servlet中使用`RequestDispatcher.forward(request, response)`方法,在JSP中使用`<jsp:forward page="...">`标签。 ### J2EE相关知识 1. **J2EE、J2SE、J2ME的区别**:J2EE面向企业级应用开发...
此外,还可以使用 `<jsp:forward>` 和 `<jsp:redirect>` 标签在JSP页面中进行重定向和转发。 5. **JavaBeans与JSP集成**: - **问题**:如何在JSP页面中使用JavaBeans? - **解释**:可以在JSP页面中声明...
- **数据类型转换**:使用`Integer.parseInt()`和`Double.parseDouble()`等方法将字符串转换为数字;数字转字符串使用`Integer.toString()`。 - **日期和时间**:`java.util.Calendar`和`java.text....
具体体现在方法重写(override)和方法重载(overload)上。 ##### StringBuffer、StringBuilder、String的区别 - **String**:不可变字符串,适合于只读字符串。 - **StringBuffer**:可变字符串,线程安全,适合...
- **日期格式化**:使用 SimpleDateFormat 类对日期进行格式化,实现日期的不同格式转换。 以上就是从给定文件的信息中提取的关键知识点,覆盖了 Struts 框架的配置和工作流程、性能优化、HTTP 协议以及 Java 编程...