当前位置: 首页 > 知识库问答 >
问题:

使SimpleDateFormat线程安全

柳景胜
2023-03-14

我有许多线程处理trade对象,其中我使用rowmapper将数据库列映射到trade对象。

我知道simpledateformat在任何Java中都不是线程安全的。因此,我在startdate中得到了一些不可预测的结果。例如,我在startdate中也看到了enddate

下面是我的代码:

public class ExampleTradeMapper {

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MMM-yyyy");

    public void map(Trade trade, ResultSet rs, int rowNum) throws SQLException {    

        trade.setStartDate(getFormattedDate(rs.getDate("START_DATE")));
        trade.setEndDate(getFormattedDate(rs.getDate("END_DATE")));
        trade.setDescription(rs.getString("DESCRIPTION"));

    }

    private String getFormattedDate(Date date) {
        try {
            if (date != null)
                return DATE_FORMAT.format(date).toUpperCase();
            else
                return null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}


public class SomeRowMapper extends TradeMapper implements RowMapper<Trade> {

    @Override
    public Trade mapRow(ResultSet rs, int rowNum) throws SQLException {

        Trade trade = new Trade();

        map(trade, rs, rowNum);

        return trade;
    }
}

我的核心池大小约为20这个应用程序的最大约50。这些线程在某个时候可以处理数据库中大约100个交易记录。

使此日期格式化线程安全的最佳方法是什么?我应该使用FastDateFormat直接替换吗?

有没有更好的替代方法来确保线程的安全性?

共有1个答案

司寇飞航
2023-03-14

不使用字符串,而是使用通过JDBC4.2或更高版本与数据库交换的java.time对象(特别是localdate)。

myResultSet.getObject(      // Exchange modern java.time html" target="_blank">objects with your database.
    "START_DATE" ,
    LocalDate.class 
)                           // Returns a `LocalDate` object.
.format(                    // Generate a `String` representing textually the content of this `LocalDate`. 
    DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US )
)

2018年1月23日

作为不可变对象,java.time对象在设计上是线程安全的。您可以缓存java.time对象,以便跨线程使用。

使SimpleDateFormat线程安全

不要。

使用几年前的现代java.time类来取代麻烦的旧的遗留日期-时间类,如SimpleDateFormatjava.util.datejava.sql.dateCalendar

java.time类被设计成线程安全的。它们使用不可变对象模式,基于原始对象的值返回新对象,而不是“改变”原始对象。

我认为没有理由在示例代码中使用字符串:不是在数据库访问代码中,也不是在业务对象(trade)中。

从JDBC4.2开始,我们可以与数据库交换java.time对象。对于类似于SQL标准date类型的数据库列,请使用类localdatelocaldate类表示一个只包含日期的值,不包含时间,也不包含时区。

myPreparedStatement.setObject( … , myLocalDate ) ;

检索。

LocalDate myLocalDate = myResultSet.getObject( … , LocalDate.class ) ;

您的trade类应该将成员变量startdateenddate保存为localdate对象,而不是字符串。

public class Trade {
    private LocalDate startDate ;
    private LocalDate endDate ;
    … 

    // Getters
    public LocalDate getStartDate() { 
        return this.startDate ;
    }
    public LocalDate getEndDate() { 
        return this.endDate;
    }
    public Period getPeriod() {  // Number of years-months-days elapsed.
        return Period.between( this.startDate , this.endDate ) ;
    }

    // Setters
    public void setStartDate( LocalDate startDateArg ) { 
        this.startDate = startDateArg ;
    }
    public void setEndDate( LocalDate endDateArg ) { 
        this.endDate = endDateArg ;
    }

    @Override
    public toString() {
        "Trade={ " + "startDate=" + this.startDate.toString() …
    }
…
}

不需要字符串,不需要格式化模式。

若要将日期-时间值交换或存储为文本,请使用标准的ISO 8601格式,而不是如问题中所示的自定义格式

在解析/生成字符串时,java.time类默认使用ISO8601格式。因此不需要指定格式模式。

LocalDate ld = LocalDate.parse( "2018-01-23" ) ; // January 23, 2018.
String s = ld.toString() ;  // Outputs 2018-01-23. 
  • formatstyle确定字符串的长度或缩写形式。
  • 区域设置来确定:
    • 用于翻译日名、月名等的人类语言。
    • 决定缩写、大写、标点符号、分隔符等问题的文化规范。

    示例:

    Locale l = Locale.CANADA_FRENCH ; 
    DateTimeFormatter f = 
        DateTimeFormatter.ofLocalizedDate( FormatStyle.FULL )
                         .withLocale( l ) ;
    String output = ld.format( f ) ;
    

    2018年janvier 23狂欢节

    现在处于维护模式的Joda-Time项目建议迁移到java.time类。

    要了解更多信息,请参阅Oracle教程。并搜索堆栈溢出以获得许多示例和解释。规范是JSR310。

    您可以直接与数据库交换java.time对象。使用与JDBC4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要java.sql.*类。

    从哪里获取java.time类?

    • Java SE 8、Java SE 9、Java SE 10及更高版本
      • 内置。
      • 带有捆绑实现的标准Java API的一部分。
      • Java 9添加了一些小功能和修补程序。
      • 大部分Java.time功能在threeten-backport中后端移植到Java6&7。
      • java.time类的Android捆绑实现的更高版本。
      • 对于早期的Android(<26),ThreeTenABP项目适用于ThreeTen-Backport(上面提到)。查看如何使用ThreeTenabp…。

      ThreeTen-Extra项目使用额外的类扩展了java.time。这个项目是将来可能添加java.time的一个试验场。您可以在这里找到一些有用的类,如intervalyearweekyearquard等等。

 类似资料:
  • 问题内容: 我对线程安全性有疑问。据我所知,SimpleDateFormat不是线程安全的。我想知道如果在spring控制器中以以下方式使用它会产生什么影响: 稍后在我的控制器功能中,我将其如下使用: 然后将calcDate添加到我的模型对象中,并返回ModelAndView。 那么用这种方式我会看到什么样的问题呢?是否只需删除static关键字即可解决任何问题,因为每个线程将使用其自己的date

  • 问题内容: 请用代码示例说明为什么SimpleDateFormat不是线程安全的。这节课有什么问题? 是SimpleDateFormat的格式功能问题吗?请提供一个在课堂上演示此错误的代码。 FastDateFormat是线程安全的。为什么?SimpleDateFormat和FastDateFormat有什么区别? 请用代码说明这个问题? 问题答案: 将中间结果存储在实例字段中。因此,如果两个线程

  • 本文向大家介绍Java多线程环境下SimpleDateFormat类安全转换,包括了Java多线程环境下SimpleDateFormat类安全转换的使用技巧和注意事项,需要的朋友参考一下 一、SimpleDateFormat类 二、线程状态和线程组 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 下面是一个解释线程安全性的示例方法: 为了提供线程安全,有几种方法,我更喜欢使用方法。然而 1.我还想知道是否可以通过对必要的变量使用来提供线程安全。如果是,我如何执行此操作? 2.Java中经常使用作为变量和方法参数来提供线程安全性,这是原因之一吗?

  • 问题内容: HttpUrlConnection线程安全吗?即,如果我有一个连接到服务器的HttpConnection实例,并且该实例被不同的线程使用(例如,尝试同时发送POST),HttpUrlConnection将如何处理这种情况?a)他们将串行发送POST,还是b)第一个线程发送POST,获取响应,然后第二个线程发送POST?如果它们以串行方式发送POST,则意味着到同一tcp连接的多个活动P

  • 假设我有一个Executors静态工厂方法的ExecutorService实例。 如果我从某个线程提交了一个调用,其中RetVal不是线程安全的本地实例化对象,那么当我从同一个线程获得()它时,我需要担心retvals的完整性吗?人们说局部变量是线程安全的,但我不确定当您返回一个本地实例化的对象并从其他线程接收它时,它是否适用。 下面是我的定制实现,我只是为了测试。您可以忽略EType枚举。