ICU-7169 Fixed DateTimePatternGenerator threading problem. Also added getFrozenInstance as @internal for now.

X-SVN-Rev: 26709
This commit is contained in:
Yoshito Umaoka 2009-09-30 22:32:48 +00:00
parent 5fd02e901c
commit ff242a51a3
2 changed files with 91 additions and 26 deletions

View File

@ -103,7 +103,7 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
}
/**
* Construct a flexible generator according to data for a given locale.
* Construct a flexible generator according to data for the default locale.
* @stable ICU 3.6
*/
public static DateTimePatternGenerator getInstance() {
@ -116,6 +116,19 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
* @stable ICU 3.6
*/
public static DateTimePatternGenerator getInstance(ULocale uLocale) {
return getFrozenInstance(uLocale).cloneAsThawed();
}
/**
* Construct a frozen instance of DateTimePatternGenerator for a
* given locale. This method returns a cached frozen instance of
* DateTimePatternGenerator, so less expensive than the regular
* factory method.
* @param uLocale The locale to pass.
* @return A frozen DateTimePatternGenerator.
* @internal
*/
public static DateTimePatternGenerator getFrozenInstance(ULocale uLocale) {
String localeKey = uLocale.toString();
DateTimePatternGenerator result = DTPNG_CACHE.get(localeKey);
if (result != null) {
@ -232,6 +245,9 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
// decimal point for seconds
DecimalFormatSymbols dfs = new DecimalFormatSymbols(uLocale);
result.setDecimal(String.valueOf(dfs.getDecimalSeparator()));
// freeze and cache
result.freeze();
DTPNG_CACHE.put(localeKey, result);
return result;
}
@ -337,6 +353,13 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
* @stable ICU 3.6
*/
public String getBestPattern(String skeleton) {
return getBestPattern(skeleton, null);
}
/*
* getBestPattern which takes optional skip matcher
*/
private String getBestPattern(String skeleton, DateTimeMatcher skipMatcher) {
//if (!isComplete) complete();
if (chineseMonthHack) {
skeleton = skeleton.replaceAll("MMM+", "MM");
@ -345,16 +368,20 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
// replace it with the default hour format char
skeleton = skeleton.replaceAll("j", String.valueOf(defaultHourFormatChar));
current.set(skeleton, fp);
String best = getBestRaw(current, -1, _distanceInfo);
if (_distanceInfo.missingFieldMask == 0 && _distanceInfo.extraFieldMask == 0) {
// we have a good item. Adjust the field types
return adjustFieldTypes(best, current, false);
String datePattern, timePattern;
synchronized(this) {
current.set(skeleton, fp);
String best = getBestRaw(current, -1, _distanceInfo, skipMatcher);
if (_distanceInfo.missingFieldMask == 0 && _distanceInfo.extraFieldMask == 0) {
// we have a good item. Adjust the field types
return adjustFieldTypes(best, current, false);
}
int neededFields = current.getFieldMask();
// otherwise break up by date and time.
datePattern = getBestAppending(current, neededFields & DATE_MASK, _distanceInfo, skipMatcher);
timePattern = getBestAppending(current, neededFields & TIME_MASK, _distanceInfo, skipMatcher);
}
int neededFields = current.getFieldMask();
// otherwise break up by date and time.
String datePattern = getBestAppending(neededFields & DATE_MASK);
String timePattern = getBestAppending(neededFields & TIME_MASK);
if (datePattern == null) return timePattern == null ? "" : timePattern;
if (timePattern == null) return datePattern;
@ -612,8 +639,7 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
if (CANONICAL_SET.contains(pattern)) {
continue;
}
skipMatcher = cur;
String trial = getBestPattern(cur.toString());
String trial = getBestPattern(cur.toString(), cur);
if (trial.equals(pattern)) {
output.add(pattern);
}
@ -1303,8 +1329,6 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
private transient DateTimeMatcher current = new DateTimeMatcher();
private transient FormatParser fp = new FormatParser();
private transient DistanceInfo _distanceInfo = new DistanceInfo();
private transient DateTimeMatcher skipMatcher = null; // only used temporarily, for internal purposes
private static final int FRACTIONAL_MASK = 1<<FRACTIONAL_SECOND;
private static final int SECOND_AND_FRACTIONAL_MASK = (1<<SECOND) | (1<<FRACTIONAL_SECOND);
@ -1322,27 +1346,27 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
* We only get called here if we failed to find an exact skeleton. We have broken it into date + time, and look for the pieces.
* If we fail to find a complete skeleton, we compose in a loop until we have all the fields.
*/
private String getBestAppending(int missingFields) {
private String getBestAppending(DateTimeMatcher source, int missingFields, DistanceInfo distInfo, DateTimeMatcher skipMatcher) {
String resultPattern = null;
if (missingFields != 0) {
resultPattern = getBestRaw(current, missingFields, _distanceInfo);
resultPattern = adjustFieldTypes(resultPattern, current, false);
resultPattern = getBestRaw(source, missingFields, distInfo, skipMatcher);
resultPattern = adjustFieldTypes(resultPattern, source, false);
while (_distanceInfo.missingFieldMask != 0) { // precondition: EVERY single field must work!
while (distInfo.missingFieldMask != 0) { // precondition: EVERY single field must work!
// special hack for SSS. If we are missing SSS, and we had ss but found it, replace the s field according to the
// number separator
if ((_distanceInfo.missingFieldMask & SECOND_AND_FRACTIONAL_MASK) == FRACTIONAL_MASK
if ((distInfo.missingFieldMask & SECOND_AND_FRACTIONAL_MASK) == FRACTIONAL_MASK
&& (missingFields & SECOND_AND_FRACTIONAL_MASK) == SECOND_AND_FRACTIONAL_MASK) {
resultPattern = adjustFieldTypes(resultPattern, current, true);
_distanceInfo.missingFieldMask &= ~FRACTIONAL_MASK; // remove bit
resultPattern = adjustFieldTypes(resultPattern, source, true);
distInfo.missingFieldMask &= ~FRACTIONAL_MASK; // remove bit
continue;
}
int startingMask = _distanceInfo.missingFieldMask;
String temp = getBestRaw(current, _distanceInfo.missingFieldMask, _distanceInfo);
temp = adjustFieldTypes(temp, current, false);
int foundMask = startingMask & ~_distanceInfo.missingFieldMask;
int startingMask = distInfo.missingFieldMask;
String temp = getBestRaw(source, distInfo.missingFieldMask, distInfo, skipMatcher);
temp = adjustFieldTypes(temp, source, false);
int foundMask = startingMask & ~distInfo.missingFieldMask;
int topField = getTopBitNumber(foundMask);
resultPattern = MessageFormat.format(getAppendFormat(topField), new Object[]{resultPattern, temp, getAppendName(topField)});
}
@ -1398,7 +1422,7 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
/**
*
*/
private String getBestRaw(DateTimeMatcher source, int includeMask, DistanceInfo missingFields) {
private String getBestRaw(DateTimeMatcher source, int includeMask, DistanceInfo missingFields, DateTimeMatcher skipMatcher) {
// if (SHOW_DISTANCE) System.out.println("Searching for: " + source.pattern
// + ", mask: " + showMask(includeMask));
int bestDistance = Integer.MAX_VALUE;

View File

@ -938,4 +938,45 @@ public class DateTimeGeneratorTest extends TestFmwk {
}
}
}
/*
* Test case for DateFormatPatternGenerator threading problem #7169
*/
public void TestT7169() {
Thread[] workers = new Thread[10];
for (int i = 0 ; i < workers.length; i++) {
workers[i] = new Thread(new Runnable() {
public void run() {
try {
for (int i = 0; i < 50; i++) {
DateTimePatternGenerator patternGenerator =
DateTimePatternGenerator.getFrozenInstance(ULocale.US);
patternGenerator.getBestPattern("MMMMd");
}
} catch (Exception e) {
errln("FAIL: Caught an exception (frozen)" + e);
}
try {
for (int i = 0; i < 50; i++) {
DateTimePatternGenerator patternGenerator =
DateTimePatternGenerator.getInstance(ULocale.US);
patternGenerator.getBestPattern("MMMMd");
}
} catch (Exception e) {
errln("FAIL: Caught an exception " + e);
}
}
});
}
for (Thread wk : workers) {
wk.start();
}
for (Thread wk : workers) {
try {
wk.join();
} catch (InterruptedException ie) {
}
}
}
}