8019623: Lack of synchronization in AppContext.getAppContext()
Reviewed-by: anthony, art
--- a/jdk/src/share/classes/sun/awt/AppContext.java Wed Oct 09 15:34:53 2013 +0400
+++ b/jdk/src/share/classes/sun/awt/AppContext.java Wed Oct 09 20:59:08 2013 +0400
@@ -167,6 +167,9 @@
*/
private static volatile AppContext mainAppContext = null;
+ private static class GetAppContextLock {};
+ private final static Object getAppContextLock = new GetAppContextLock();
+
/*
* The hash map associated with this AppContext. A private delegate
* is used instead of subclassing HashMap so as to avoid all of
@@ -309,14 +312,16 @@
// if no contexts have been created yet. This covers standalone apps
// and excludes applets because by the time applet starts
// a number of contexts have already been created by the plugin.
- if (numAppContexts.get() == 0) {
- if (System.getProperty("javaplugin.version") == null &&
- System.getProperty("javawebstart.version") == null) {
- initMainAppContext();
- } else if (System.getProperty("javafx.version") != null &&
- threadGroup.getParent() != null) {
- // Swing inside JavaFX case
- SunToolkit.createNewAppContext();
+ synchronized (getAppContextLock) {
+ if (numAppContexts.get() == 0) {
+ if (System.getProperty("javaplugin.version") == null &&
+ System.getProperty("javawebstart.version") == null) {
+ initMainAppContext();
+ } else if (System.getProperty("javafx.version") != null &&
+ threadGroup.getParent() != null) {
+ // Swing inside JavaFX case
+ SunToolkit.createNewAppContext();
+ }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/awt/AppContext/MultiThread/MultiThreadTest.java Wed Oct 09 20:59:08 2013 +0400
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8019623
+ * @summary Tests that AppContext.getAppContext() works correctly in multi-threads scenario.
+ * @author Leonid Romanov
+ */
+
+import sun.awt.AppContext;
+
+public class MultiThreadTest {
+ private static final int NUM_THREADS = 2;
+
+ private static AppContextGetter[] getters = new AppContextGetter[NUM_THREADS];
+
+ public static void main(String[] args) {
+ createAndStartThreads();
+ compareAppContexts();
+ }
+
+ private static void createAndStartThreads() {
+ ThreadGroup systemGroup = getSystemThreadGroup();
+ for (int i = 0; i < NUM_THREADS; ++i) {
+ ThreadGroup tg = new ThreadGroup(systemGroup, "AppContextGetter" + i);
+ getters[i] = new AppContextGetter(tg);
+ }
+
+ for (int i = 0; i < NUM_THREADS; ++i) {
+ getters[i].start();
+ }
+
+ for (int i = 0; i < NUM_THREADS; ++i) {
+ try {
+ getters[i].join();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ }
+
+ private static ThreadGroup getSystemThreadGroup() {
+ ThreadGroup currentThreadGroup =
+ Thread.currentThread().getThreadGroup();
+ ThreadGroup parentThreadGroup = currentThreadGroup.getParent();
+ while (parentThreadGroup != null) {
+ currentThreadGroup = parentThreadGroup;
+ parentThreadGroup = currentThreadGroup.getParent();
+ }
+
+ return currentThreadGroup;
+ }
+
+ private static void compareAppContexts() {
+ AppContext ctx = getters[0].getAppContext();
+ for (int i = 1; i < NUM_THREADS; ++i) {
+ if (!ctx.equals(getters[i].getAppContext())) {
+ throw new RuntimeException("Unexpected AppContexts difference, could be a race condition");
+ }
+ }
+ }
+
+ private static class AppContextGetter extends Thread {
+ private AppContext appContext;
+
+ public AppContextGetter(ThreadGroup tg) {
+ super(tg, tg.getName());
+ }
+
+ AppContext getAppContext() {
+ return appContext;
+ }
+
+ @Override
+ public void run() {
+ appContext = AppContext.getAppContext();
+ }
+ }
+}