8019623: Lack of synchronization in AppContext.getAppContext()
authorleonidr
Wed, 09 Oct 2013 20:59:08 +0400
changeset 21242 dd191df75e13
parent 21241 dc8cd488885d
child 21243 1bb93b4654ef
8019623: Lack of synchronization in AppContext.getAppContext() Reviewed-by: anthony, art
jdk/src/share/classes/sun/awt/AppContext.java
jdk/test/sun/awt/AppContext/MultiThread/MultiThreadTest.java
--- 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();
+        }
+    }
+}