DateFormat或Calender.getInstance有时会返回随机值

时间:2016-08-31 14:04:50

标签: java android multithreading time thread-safety

now()的以下代码对对象执行两次。一次表示它的创建,另一次表示它何时被写入数据库。

在受控测试中,我设法可靠地重现了日期彼此之间变化很大的错误。某些日期似乎有正确的日期,但是00:00:00或接近00:00:00

其他人似乎相对较弱,从1小时到16周甚至几周不等。我也有未来的时间。 Calendar.getInstance.getTime()应该等同于System.getCurrentTimeMillis(),让后者在一段时间内返回未来的时间后会担心一些。

我还没找到任何东西,并会进一步调查这个问题并在此报告我的发现。

private static DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

public static String calendarToDb(Calendar cal) {
    if (cal == null) {
        return null;
    }
    return simpleDateFormat.format(cal.getTime());
}

public static String now() {
    return calendarToDb(Calendar.getInstance());
}

这是android-monitor日志的相关部分。这是一个真实的设备,而不是模拟器。 M代表MessageManager,P代表ContentProvider

08-30 18:07:17.267 M: main             starttime  = 2016-01-01T00:07:00+0100\
08-30 18:07:17.306 P: AsyncQueryWorker CreateTime = 2016-08-30T18:07:17+0200\
08-30 18:07:18.326 M: main             starttime  = 2016-01-01T00:00:00+0200\
08-30 18:07:18.371 P: AsyncQueryWorker CreateTime = 2016-08-30T18:07:18+0200\
08-30 18:07:19.898 M: main             starttime  = 2016-08-30T18:07:19+0200\
08-30 18:07:19.920 P: AsyncQueryWorker CreateTime = 2016-08-30T00:00:00+0100\

我的数据库中有更多数据看起来更奇怪,根本不应该发生。

2 个答案:

答案 0 :(得分:3)

问题似乎很可能出现在静态

Sub SearchFolders()
Dim fso As Object
Dim fld As Object
Dim strSearch As String ' Keyword to search for
Dim strPath As String ' Filepath of folder to search
Dim strFile As String ' current file that the loop is searching through
Dim wOut As Worksheet ' Worksheet to display results
Dim wbk As Workbook ' Workbook to be searched
Dim wks As Worksheet ' Worksheet to be searched
Dim lRow As Integer
Dim rFound As Range
Dim strFirstAddress As String

Application.ScreenUpdating = False

'Change as desired
strPath = "\\ant\dept-eu\LTN1\Techies Information\aa Eng daily log"
strSearch = InputBox("Insert Keyword to search")

Set wOut = Sheet1
lRow = 1
With wOut
    Sheet1.Cells.Clear
    .Cells(lRow, 1) = "Workbook"
    .Cells(lRow, 2) = "Worksheet"
    .Cells(lRow, 3) = "Text in Cell"
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set fld = fso.GetFolder(strPath)

    strFile = Dir(strPath & "\*.xls*")
    Do While strFile <> ""
        Set wbk = Workbooks.Open _
          (Filename:=strPath & "\" & strFile, _
          UpdateLinks:=0, _
          ReadOnly:=True, _
          AddToMRU:=False)

        For Each wks In wbk.Worksheets ' for each worksheet
            Set rFound = wks.UsedRange.Find(strSearch) ' setting variable to first result in find function
            If Not rFound Is Nothing Then ' if something is found
                strFirstAddress = rFound.Address ' set first address to that cell's address
            End If
            Do
                If rFound Is Nothing Then ' if nothing was found
                    Exit Do ' exit loop
                Else ' if something was found then add the details to the table
                    lRow = lRow + 1
                    .Cells(lRow, 1) = wbk.Name
                    .Cells(lRow, 2) = wks.Name
                    .Cells(lRow, 3) = rFound.Value
                End If
               Set rFound = wks.Cells.FindNext(After:=rFound)  ' sets rfound vaiable to next found value
            Loop While strFirstAddress <> rFound.Address ' once the find function gets back to the first address then exit the loop

        Next ' next worksheet in file

        wbk.Close (False)
        strFile = Dir
    Loop
    .Columns("A:D").EntireColumn.AutoFit
End With
MsgBox "Done"

ExitHandler:
Set wOut = Nothing
Set wks = Nothing
Set wbk = Nothing
Set fld = Nothing
Set fso = Nothing
Application.ScreenUpdating = True
Exit Sub

如下所述: Why is Java's SimpleDateFormat not thread-safe?

存储中间结果,如果多个线程使用相同的实例(由于静态,它们会执行)。时间可以在方法执行期间部分重置,这会扭曲当前处理的结果。

解决方案是每次都返回新实例。

答案 1 :(得分:1)

Avoid legacy date-time classes

The Answer by HopefullyHelpful is correct, and should be accepted. You are likely seeing errors due to the lack of thread-safety in the old date-time classes. This is one of many reasons to avoid these troublesome old legacy date-time classes.

Instead you should be using the java.time classes. The java.time classes have thread-safety baked-in.

ISO 8601

Your input strings happen to comply with the ISO 8601 standard for date-time formats.

The java.time classes use ISO 8601 formats by default when parsing/generating Strings. So you should not need to specify a formatting pattern but for a bug in the current Java 8 implementation. Currently the lack of a colon in the offset-from-UTC causes parsing to fail by default. Should be fixed in Java 9. While in Java 8 specify a pattern with DateTimeFormatter and DateTimeFormatterBuilder.

String input = "2016-08-30T18:07:17+0200";

DateTimeFormatterBuilder fb = new DateTimeFormatterBuilder ().append ( DateTimeFormatter.ISO_LOCAL_DATE_TIME ).appendOffset ( "+HHMM" , "Z" );
DateTimeFormatter f = fb.toFormatter ();

OffsetDateTime

Your input strings indicate an offset-from-UTC but not a full time zone. So we parse as OffsetDateTime objects.

In Java 9 and later, parse directly:

OffsetDateTime odt = OffsetDateTime.parse ( input );

In Java 8, use the DateTimeFormatter object built above.

OffsetDateTime odt = OffsetDateTime.parse ( input , f );

Dump to console.

System.out.println ( "input: " + input + " | odt: " + odt );

input: 2016-08-30T18:07:17+0200 | odt: 2016-08-30T18:07:17+02:00