228 if (dups) { |
227 if (dups) { |
229 errln("Resource bundle not caching some classes properly"); |
228 errln("Resource bundle not caching some classes properly"); |
230 } |
229 } |
231 } |
230 } |
232 |
231 |
233 /** |
|
234 * Previous versions of ResourceBundle exhibited the following caching behavior. |
|
235 * Assume the class Bug4168625Resource_en exists. Bug4168625Resource_en_US does |
|
236 * not. Two threads, ThreadA and ThreadB both try to get the same bundle. |
|
237 * <P> |
|
238 * <pre> |
|
239 * ThreadA.getBundle("Bug4168625Resource", new Locale("en", "US")); |
|
240 * A-->try to load Bug4168625Resource_en_US |
|
241 * ThreadB.getBundle("Bug4168625Resource", new Locale("en", "US")); |
|
242 * B-->try to load Bug4168625Resource_en_US |
|
243 * B-->load Bug4168625Resource_en (#1) |
|
244 * A-->load Bug4168625Resource_en (#2) |
|
245 * A-->cache Bug4168625Resource_en (#2) as Bug4168625Resource_en |
|
246 * A-->cache Bug4168625Resource_en (#2) as Bug4168625Resource_en_US |
|
247 * A-->return Bug4168625Resource_en (#2) |
|
248 * B-->cache Bug4168625Resource_en (#1) as Bug4168625Resource_en |
|
249 * B-->cache Bug4168625Resource_en (#1) as Bug4168625Resource_en_US |
|
250 * B-->return Bug4168625Resource_en (#1) |
|
251 * </pre> |
|
252 * <P> |
|
253 * Both threads try and fail to load Bug4168625Resource_en_US. Both |
|
254 * threads load Bug4168625Resource_en. Both threads get their own copy |
|
255 * of the Bug4168625Resource_en resource. |
|
256 * |
|
257 * The desired behavior is as follows: |
|
258 * <P> |
|
259 * <pre> |
|
260 * ThreadA.getBundle("Bug4168625Resource", new Locale("en", "US")); |
|
261 * A-->try to load Bug4168625Resource_en_US |
|
262 * ThreadB.getBundle("Bug4168625Resource", new Locale("en", "US")); |
|
263 * B-->try to load Bug4168625Resource_en_US |
|
264 * B-->load Bug4168625Resource_en |
|
265 * A-->load Bug4168625Resource_en (block in ResourceBundle.getBundle) |
|
266 * B-->cache Bug4168625Resource_en as Bug4168625Resource_en |
|
267 * B-->cache Bug4168625Resource_en as Bug4168625Resource_en_US |
|
268 * A-->return Bug4168625Resource_en |
|
269 * B-->return Bug4168625Resource_en |
|
270 * </pre> |
|
271 * <P> |
|
272 * Note that both threads return the same bundle object. |
|
273 */ |
|
274 public void testConcurrentLoading1() throws Exception { |
|
275 final Loader loader = new Loader( new String[] { "Bug4168625Class" }, new String[] { "Bug4168625Resource3_en_US", "Bug4168625Resource3_en_CA" }); |
|
276 final Class c = loader.loadClass("Bug4168625Class"); |
|
277 final Bug4168625Getter test = (Bug4168625Getter)c.newInstance(); |
|
278 |
|
279 //both threads want the same resource |
|
280 ConcurrentLoadingThread thread1 = new ConcurrentLoadingThread(loader, test, new Locale("en", "US")); |
|
281 ConcurrentLoadingThread thread2 = new ConcurrentLoadingThread(loader, test, new Locale("en", "US")); |
|
282 |
|
283 thread1.start(); //start thread 1 |
|
284 loader.waitForNotify(1); //wait for thread1 to do getBundle & block in loader |
|
285 thread2.start(); //start second thread |
|
286 loader.waitForNotify(2, 1000); //wait until thread2 blocks somewhere in getBundle |
|
287 thread1.ping(); //continue both threads |
|
288 thread2.ping(); |
|
289 |
|
290 thread1.join(); //wait unitl both threads complete |
|
291 thread2.join(); |
|
292 |
|
293 //Now, examine the class loads that were done. |
|
294 loader.logClasses("Classes loaded after completion of both threads:"); |
|
295 |
|
296 boolean dups = false; |
|
297 for (int i = loader.loadedClasses.size() - 1; i >= 0 ; i--) { |
|
298 final Object item = loader.loadedClasses.elementAt(i); |
|
299 loader.loadedClasses.removeElementAt(i); |
|
300 if (loader.loadedClasses.contains(item)) { |
|
301 logln("Resource loaded more than once: "+item); |
|
302 dups = true; |
|
303 } |
|
304 } |
|
305 if (dups) { |
|
306 errln("ResourceBundle loaded some classes multiple times"); |
|
307 } |
|
308 } |
|
309 |
|
310 private class ConcurrentLoadingThread extends Thread { |
232 private class ConcurrentLoadingThread extends Thread { |
311 private Loader loader; |
233 private Loader loader; |
312 public Object bundle; |
234 public Object bundle; |
313 private Bug4168625Getter test; |
235 private Bug4168625Getter test; |
314 private Locale locale; |
236 private Locale locale; |
353 |
275 |
354 /** |
276 /** |
355 * This test ensures that multiple resources can be loading at the same |
277 * This test ensures that multiple resources can be loading at the same |
356 * time as long as they don't depend on each other in some way. |
278 * time as long as they don't depend on each other in some way. |
357 */ |
279 */ |
358 public void testConcurrentLoading2() throws Exception { |
280 public void testConcurrentLoading() throws Exception { |
359 final Loader loader = new Loader( new String[] { "Bug4168625Class" }, new String[] { "Bug4168625Resource3_en_US", "Bug4168625Resource3_en_CA" }); |
281 final Loader loader = new Loader( new String[] { "Bug4168625Class" }, new String[] { "Bug4168625Resource3_en_US", "Bug4168625Resource3_en_CA" }); |
360 final Class c = loader.loadClass("Bug4168625Class"); |
282 final Class c = loader.loadClass("Bug4168625Class"); |
361 final Bug4168625Getter test = (Bug4168625Getter)c.newInstance(); |
283 final Bug4168625Getter test = (Bug4168625Getter)c.newInstance(); |
362 |
284 |
363 ConcurrentLoadingThread thread1 = new ConcurrentLoadingThread(loader, test, new Locale("en", "CA")); |
285 ConcurrentLoadingThread thread1 = new ConcurrentLoadingThread(loader, test, new Locale("en", "CA")); |