ICU-7169 Fixed DateTimePatternGenerator threading problem. Also added getFrozenInstance as @internal for now.
X-SVN-Rev: 26709
This commit is contained in:
parent
5fd02e901c
commit
ff242a51a3
@ -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;
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user