# HG changeset patch # User leonidr # Date 1381337948 -14400 # Node ID dd191df75e13a4a81d9f0aa12c2f79521a80d3cd # Parent dc8cd488885df9fc3e3fc0f0ab9d94dcbb639f31 8019623: Lack of synchronization in AppContext.getAppContext() Reviewed-by: anthony, art diff -r dc8cd488885d -r dd191df75e13 jdk/src/share/classes/sun/awt/AppContext.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(); + } } } diff -r dc8cd488885d -r dd191df75e13 jdk/test/sun/awt/AppContext/MultiThread/MultiThreadTest.java --- /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(); + } + } +}