mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-11669 Thread safety of DateIntervalFormat::format()
X-SVN-Rev: 38157
This commit is contained in:
parent
0183cad1d7
commit
09819eab73
2 changed files with 90 additions and 7 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2015, International Business Machines
|
||||
* Copyright (C) 2008-2016, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
@ -247,6 +247,12 @@ import com.ibm.icu.util.ULocale.Category;
|
|||
*
|
||||
*
|
||||
* </pre>
|
||||
* <h4>Synchronization</h4>
|
||||
*
|
||||
* The format methods of DateIntervalFormat may be used concurrently from multiple threads.
|
||||
* Functions that alter the state of a DateIntervalFormat object (setters)
|
||||
* may not be used concurrently with any other functions.
|
||||
*
|
||||
* @stable ICU 4.0
|
||||
*/
|
||||
|
||||
|
@ -296,7 +302,9 @@ public class DateIntervalFormat extends UFormat {
|
|||
private DateIntervalInfo fInfo;
|
||||
|
||||
/*
|
||||
* The DateFormat object used to format single pattern
|
||||
* The DateFormat object used to format single pattern.
|
||||
* Because fDateFormat is modified during format operations, all
|
||||
* access to it from logically const, thread safe functions must be synchronized.
|
||||
*/
|
||||
private SimpleDateFormat fDateFormat;
|
||||
|
||||
|
@ -304,6 +312,8 @@ public class DateIntervalFormat extends UFormat {
|
|||
* The 2 calendars with the from and to date.
|
||||
* could re-use the calendar in fDateFormat,
|
||||
* but keeping 2 calendars make it clear and clean.
|
||||
* Because these Calendars are modified during format operations, all
|
||||
* access to them from logically const, thread safe functions must be synchronized.
|
||||
*/
|
||||
private Calendar fFromCalendar;
|
||||
private Calendar fToCalendar;
|
||||
|
@ -559,7 +569,7 @@ public class DateIntervalFormat extends UFormat {
|
|||
* @return A copy of the object.
|
||||
* @stable ICU 4.0
|
||||
*/
|
||||
public Object clone()
|
||||
public synchronized Object clone()
|
||||
{
|
||||
DateIntervalFormat other = (DateIntervalFormat) super.clone();
|
||||
other.fDateFormat = (SimpleDateFormat) fDateFormat.clone();
|
||||
|
@ -618,7 +628,7 @@ public class DateIntervalFormat extends UFormat {
|
|||
* @return Reference to 'appendTo' parameter.
|
||||
* @stable ICU 4.0
|
||||
*/
|
||||
public final StringBuffer format(DateInterval dtInterval,
|
||||
public final synchronized StringBuffer format(DateInterval dtInterval,
|
||||
StringBuffer appendTo,
|
||||
FieldPosition fieldPosition)
|
||||
{
|
||||
|
@ -686,7 +696,7 @@ public class DateIntervalFormat extends UFormat {
|
|||
* @throws IllegalArgumentException if the two calendars are not equivalent.
|
||||
* @stable ICU 4.0
|
||||
*/
|
||||
public final StringBuffer format(Calendar fromCalendar,
|
||||
public final synchronized StringBuffer format(Calendar fromCalendar,
|
||||
Calendar toCalendar,
|
||||
StringBuffer appendTo,
|
||||
FieldPosition pos)
|
||||
|
@ -1008,7 +1018,7 @@ public class DateIntervalFormat extends UFormat {
|
|||
* this date interval formatter.
|
||||
* @stable ICU 4.0
|
||||
*/
|
||||
public DateFormat getDateFormat()
|
||||
public synchronized DateFormat getDateFormat()
|
||||
{
|
||||
return (DateFormat)fDateFormat.clone();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2001-2015, International Business Machines Corporation and *
|
||||
* Copyright (C) 2001-2016, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
@ -14,7 +14,10 @@ package com.ibm.icu.dev.test.format;
|
|||
|
||||
import java.text.FieldPosition;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.ibm.icu.impl.Utility;
|
||||
|
@ -1714,4 +1717,74 @@ public class DateIntervalFormatTest extends com.ibm.icu.dev.test.TestFmwk {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestTicket11669 - Check the thread safety of DateIntervalFormat.format().
|
||||
// This test failed with ICU 56.
|
||||
|
||||
public void TestTicket11669 () {
|
||||
// These final variables are accessed directly by the concurrent threads.
|
||||
final DateIntervalFormat formatter = DateIntervalFormat.getInstance(DateFormat.YEAR_MONTH_DAY, ULocale.US);
|
||||
final ArrayList<DateInterval> testIntervals = new ArrayList<DateInterval>();
|
||||
final ArrayList<String>expectedResults = new ArrayList<String>();
|
||||
|
||||
// Create and save the input test data.
|
||||
TimeZone tz = TimeZone.getTimeZone("Americal/Los_Angeles");
|
||||
Calendar intervalStart = Calendar.getInstance(tz, ULocale.US);
|
||||
Calendar intervalEnd = Calendar.getInstance(tz, ULocale.US);
|
||||
intervalStart.set(2009, 6, 1);
|
||||
intervalEnd.set(2009, 6, 2);
|
||||
testIntervals.add(new DateInterval(intervalStart.getTimeInMillis(), intervalEnd.getTimeInMillis()));
|
||||
intervalStart.set(2015, 2, 27);
|
||||
intervalEnd.set(2015, 3, 1);
|
||||
testIntervals.add(new DateInterval(intervalStart.getTimeInMillis(), intervalEnd.getTimeInMillis()));
|
||||
|
||||
// Run the formatter single-threaded to create and save the expected results.
|
||||
for (DateInterval interval: testIntervals) {
|
||||
FieldPosition pos = new FieldPosition(0);
|
||||
StringBuffer result = new StringBuffer();
|
||||
formatter.format(interval, result, pos);
|
||||
expectedResults.add(result.toString());
|
||||
}
|
||||
|
||||
class TestThread extends Thread {
|
||||
public String errorMessage;
|
||||
public void run() {
|
||||
for (int loop=0; loop < 2000; ++loop) {
|
||||
ListIterator<String> expectedItr = expectedResults.listIterator();
|
||||
for (DateInterval interval: testIntervals) {
|
||||
String expected = expectedItr.next();
|
||||
FieldPosition pos = new FieldPosition(0);
|
||||
StringBuffer result = new StringBuffer();
|
||||
formatter.format(interval, result, pos);
|
||||
if (!expected.equals(result.toString())) {
|
||||
// Note: The ICU test framework doesn't support reporting failures from within a sub-thread.
|
||||
// Save the failure for the main thread to pick up later.
|
||||
errorMessage = String.format("Expected \"%s\", actual \"%s\"", expected, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<TestThread> threads = new ArrayList<TestThread>();
|
||||
for (int i=0; i<4; ++i) {
|
||||
threads.add(new TestThread());
|
||||
}
|
||||
for (Thread t: threads) {
|
||||
t.start();
|
||||
}
|
||||
for (TestThread t: threads) {
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException e) {
|
||||
fail("Unexpected exception: " + e.toString());
|
||||
}
|
||||
if (t.errorMessage != null) {
|
||||
fail(t.errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue