8054991: sun.font.GlyphList uses broken double-checked locking
Reviewed-by: psadhukhan, aivanov
--- a/jdk/src/java.desktop/share/classes/sun/font/GlyphList.java Mon Jul 18 09:53:59 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/font/GlyphList.java Mon Jul 18 12:15:53 2016 -0700
@@ -28,6 +28,7 @@
import java.awt.Font;
import java.awt.font.GlyphVector;
import java.awt.font.FontRenderContext;
+import java.util.concurrent.atomic.AtomicBoolean;
import sun.java2d.loops.FontInfo;
/*
@@ -151,8 +152,8 @@
* occur and if it did, it would just lead to some extra garbage being
* created.
*/
- private static GlyphList reusableGL = new GlyphList();
- private static boolean inUse;
+ private static final GlyphList reusableGL = new GlyphList();
+ private static final AtomicBoolean inUse = new AtomicBoolean();
void ensureCapacity(int len) {
@@ -184,24 +185,10 @@
// }
public static GlyphList getInstance() {
- /* The following heuristic is that if the reusable instance is
- * in use, it probably still will be in a micro-second, so avoid
- * synchronising on the class and just allocate a new instance.
- * The cost is one extra boolean test for the normal case, and some
- * small number of cases where we allocate an extra object when
- * in fact the reusable one would be freed very soon.
- */
- if (inUse) {
+ if (inUse.compareAndSet(false, true)) {
+ return reusableGL;
+ } else {
return new GlyphList();
- } else {
- synchronized(GlyphList.class) {
- if (inUse) {
- return new GlyphList();
- } else {
- inUse = true;
- return reusableGL;
- }
- }
}
}
@@ -212,17 +199,10 @@
* will be discarded so the re-allocation overhead is high.
*/
// public static GlyphList getInstance(int sz) {
-// if (inUse) {
-// return new GlyphList(sz);
+// if (inUse.compareAndSet(false, true) {
+// return reusableGL;
// } else {
-// synchronized(GlyphList.class) {
-// if (inUse) {
-// return new GlyphList();
-// } else {
-// inUse = true;
-// return reusableGL;
-// }
-// }
+// return new GlyphList(sz);
// }
// }
@@ -423,7 +403,7 @@
}
usePositions = false;
strikelist = null; // remove reference to the strike list
- inUse = false;
+ inUse.set(false);
}
}