使 SimpleDateFormat 线程安全

M06*_*06H 3 java multithreading thread-safety simpledateformat

我有许多线程处理Trade对象,我使用 aRowMapper将数据库列映射到Trade对象。

我知道SimpleDateFormat在任何 Java 中都不是线程安全的。结果,我在startDate. 例如,我看到日期endDate也在startDate.

这是我的代码:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

对于这个应用程序,我的核心池大小约为 20,最大约为 50。这些线程有时可以处理来自数据库的大约 100 条交易记录。

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

有没有更好的替代方法来使这个线程安全?

Bas*_*que 6

tl;博士

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

myResultSet.getObject(      // Exchange modern java.time 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 )
)
Run Code Online (Sandbox Code Playgroud)

2018 年 1 月 23 日

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

时间

使 SimpleDateFormat 线程安全

别。

利用现代java.time类,年前取代了麻烦的旧的遗留日期时间类,如SimpleDateFormatjava.util.Datejava.sql.Date,和Calendar

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

使用智能对象,而不是哑弦

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

JDBC

从 JDBC 4.2 开始,我们可以与数据库交换java.time对象。对于类型类似于 SQL 标准的数据库列DATE,请使用类LocalDate. 该LocalDate级表示没有时间一天和不同时区的日期,唯一的价值。

myPreparedStatement.setObject( … , myLocalDate ) ;
Run Code Online (Sandbox Code Playgroud)

恢复。

LocalDate myLocalDate = myResultSet.getObject( … , LocalDate.class ) ;
Run Code Online (Sandbox Code Playgroud)

业务对象

您的Trade类应该将成员变量startDate&endDate作为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() …
    }
…
}
Run Code Online (Sandbox Code Playgroud)

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

字符串

要将日期时间值交换或存储为文本,请使用标准ISO 8601格式而不是您的问题中看到的自定义格式。

java.time类解析/生成的字符串时默认使用ISO 8601种格式。所以不需要指定格式模式。

LocalDate ld = LocalDate.parse( "2018-01-23" ) ; // January 23, 2018.
String s = ld.toString() ;  // Outputs 2018-01-23. 
Run Code Online (Sandbox Code Playgroud)

为了在用户界面中呈现,让java.time自动本地化。要本地化,请指定:

  • FormatStyle 确定字符串的长度或缩写。
  • Locale 确定:
    • 用于翻译日名、月名等的人类语言
    • 决定缩写、大写、标点符号、分隔符等问题的文化规范

例子:

Locale l = Locale.CANADA_FRENCH ; 
DateTimeFormatter f = 
    DateTimeFormatter.ofLocalizedDate( FormatStyle.FULL )
                     .withLocale( l ) ;
String output = ld.format( f ) ;
Run Code Online (Sandbox Code Playgroud)

狂欢节 2018 年 1 月 23 日

DateTimeFormatter班是线程安全的,在设计上,作为不可变对象。您可以持有一个跨线程使用的实例。


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

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

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

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

从哪里获得 java.time 类?

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多