alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (AWTAutoShutdown.java)

This example Java source code file (AWTAutoShutdown.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

awt, awt\-shutdown, awtautoshutdown, awtevent, hashset, interruptedexception, map, mapped, object, platformlogger, runnable, safety_timeout, set, suppresswarnings, thread, util

The AWTAutoShutdown.java Java example source code

/*
 * Copyright (c) 2000, 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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.
 */

package sun.awt;

import java.awt.AWTEvent;

import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;

import sun.util.logging.PlatformLogger;

/**
 * This class is to let AWT shutdown automatically when a user is done
 * with AWT. It tracks AWT state using the following parameters:
 * <ul>
 * <li>peerMap - the map between the existing peer objects
 *     and their associated targets
 * <li>toolkitThreadBusy - whether the toolkit thread
 *     is waiting for a new native event to appear in its queue
 *     or is dispatching an event
 * <li>busyThreadSet - a set of all the event dispatch
 *     threads that are busy at this moment, i.e. those that are not
 *     waiting for a new event to appear in their event queue.
 * </ul>

* AWT is considered to be in ready-to-shutdown state when * <code>peerMap is empty and toolkitThreadBusy * is false and <code>busyThreadSet is empty. * The internal AWTAutoShutdown logic secures that the single non-daemon * thread (<code>blockerThread) is running when AWT is not in * ready-to-shutdown state. This blocker thread is to prevent AWT from * exiting since the toolkit thread is now daemon and all the event * dispatch threads are started only when needed. Once it is detected * that AWT is in ready-to-shutdown state this blocker thread waits * for a certain timeout and if AWT state doesn't change during timeout * this blocker thread terminates all the event dispatch threads and * exits. */ public final class AWTAutoShutdown implements Runnable { private static final AWTAutoShutdown theInstance = new AWTAutoShutdown(); /** * This lock object is used to synchronize shutdown operations. */ private final Object mainLock = new Object(); /** * This lock object is to secure that when a new blocker thread is * started it will be the first who acquire the main lock after * the thread that created the new blocker released the main lock * by calling lock.wait() to wait for the blocker to start. */ private final Object activationLock = new Object(); /** * This set keeps references to all the event dispatch threads that * are busy at this moment, i.e. those that are not waiting for a * new event to appear in their event queue. * Access is synchronized on the main lock object. */ private final Set<Thread> busyThreadSet = new HashSet<>(7); /** * Indicates whether the toolkit thread is waiting for a new native * event to appear or is dispatching an event. */ private boolean toolkitThreadBusy = false; /** * This is a map between components and their peers. * we should work with in under activationLock&mainLock lock. */ private final Map<Object, Object> peerMap = new IdentityHashMap<>(); /** * References the alive non-daemon thread that is currently used * for keeping AWT from exiting. */ private Thread blockerThread = null; /** * We need this flag to secure that AWT state hasn't changed while * we were waiting for the safety timeout to pass. */ private boolean timeoutPassed = false; /** * Once we detect that AWT is ready to shutdown we wait for a certain * timeout to pass before stopping event dispatch threads. */ private static final int SAFETY_TIMEOUT = 1000; /** * Constructor method is intentionally made private to secure * a single instance. Use getInstance() to reference it. * * @see AWTAutoShutdown#getInstance */ private AWTAutoShutdown() {} /** * Returns reference to a single AWTAutoShutdown instance. */ public static AWTAutoShutdown getInstance() { return theInstance; } /** * Notify that the toolkit thread is not waiting for a native event * to appear in its queue. * * @see AWTAutoShutdown#notifyToolkitThreadFree * @see AWTAutoShutdown#setToolkitBusy * @see AWTAutoShutdown#isReadyToShutdown */ public static void notifyToolkitThreadBusy() { getInstance().setToolkitBusy(true); } /** * Notify that the toolkit thread is waiting for a native event * to appear in its queue. * * @see AWTAutoShutdown#notifyToolkitThreadFree * @see AWTAutoShutdown#setToolkitBusy * @see AWTAutoShutdown#isReadyToShutdown */ public static void notifyToolkitThreadFree() { getInstance().setToolkitBusy(false); } /** * Add a specified thread to the set of busy event dispatch threads. * If this set already contains the specified thread or the thread is null, * the call leaves this set unchanged and returns silently. * * @param thread thread to be added to this set, if not present. * @see AWTAutoShutdown#notifyThreadFree * @see AWTAutoShutdown#isReadyToShutdown */ public void notifyThreadBusy(final Thread thread) { if (thread == null) { return; } synchronized (activationLock) { synchronized (mainLock) { if (blockerThread == null) { activateBlockerThread(); } else if (isReadyToShutdown()) { mainLock.notifyAll(); timeoutPassed = false; } busyThreadSet.add(thread); } } } /** * Remove a specified thread from the set of busy event dispatch threads. * If this set doesn't contain the specified thread or the thread is null, * the call leaves this set unchanged and returns silently. * * @param thread thread to be removed from this set, if present. * @see AWTAutoShutdown#notifyThreadBusy * @see AWTAutoShutdown#isReadyToShutdown */ public void notifyThreadFree(final Thread thread) { if (thread == null) { return; } synchronized (activationLock) { synchronized (mainLock) { busyThreadSet.remove(thread); if (isReadyToShutdown()) { mainLock.notifyAll(); timeoutPassed = false; } } } } /** * Notify that the peermap has been updated, that means a new peer * has been created or some existing peer has been disposed. * * @see AWTAutoShutdown#isReadyToShutdown */ void notifyPeerMapUpdated() { synchronized (activationLock) { synchronized (mainLock) { if (!isReadyToShutdown() && blockerThread == null) { activateBlockerThread(); } else { mainLock.notifyAll(); timeoutPassed = false; } } } } /** * Determine whether AWT is currently in ready-to-shutdown state. * AWT is considered to be in ready-to-shutdown state if * <code>peerMap is empty and toolkitThreadBusy * is false and <code>busyThreadSet is empty. * * @return true if AWT is in ready-to-shutdown state. */ private boolean isReadyToShutdown() { return (!toolkitThreadBusy && peerMap.isEmpty() && busyThreadSet.isEmpty()); } /** * Notify about the toolkit thread state change. * * @param busy true if the toolkit thread state changes from idle * to busy. * @see AWTAutoShutdown#notifyToolkitThreadBusy * @see AWTAutoShutdown#notifyToolkitThreadFree * @see AWTAutoShutdown#isReadyToShutdown */ private void setToolkitBusy(final boolean busy) { if (busy != toolkitThreadBusy) { synchronized (activationLock) { synchronized (mainLock) { if (busy != toolkitThreadBusy) { if (busy) { if (blockerThread == null) { activateBlockerThread(); } else if (isReadyToShutdown()) { mainLock.notifyAll(); timeoutPassed = false; } toolkitThreadBusy = busy; } else { toolkitThreadBusy = busy; if (isReadyToShutdown()) { mainLock.notifyAll(); timeoutPassed = false; } } } } } } } /** * Implementation of the Runnable interface. * Incapsulates the blocker thread functionality. * * @see AWTAutoShutdown#isReadyToShutdown */ public void run() { Thread currentThread = Thread.currentThread(); boolean interrupted = false; synchronized (mainLock) { try { /* Notify that the thread is started. */ mainLock.notifyAll(); while (blockerThread == currentThread) { mainLock.wait(); timeoutPassed = false; /* * This loop is introduced to handle the following case: * it is possible that while we are waiting for the * safety timeout to pass AWT state can change to * not-ready-to-shutdown and back to ready-to-shutdown. * In this case we have to wait once again. * NOTE: we shouldn't break into the outer loop * in this case, since we may never be notified * in an outer infinite wait at this point. */ while (isReadyToShutdown()) { if (timeoutPassed) { timeoutPassed = false; blockerThread = null; break; } timeoutPassed = true; mainLock.wait(SAFETY_TIMEOUT); } } } catch (InterruptedException e) { interrupted = true; } finally { if (blockerThread == currentThread) { blockerThread = null; } } } if (!interrupted) { AppContext.stopEventDispatchThreads(); } } @SuppressWarnings("serial") static AWTEvent getShutdownEvent() { return new AWTEvent(getInstance(), 0) { }; } /** * Creates and starts a new blocker thread. Doesn't return until * the new blocker thread starts. */ private void activateBlockerThread() { Thread thread = new Thread(this, "AWT-Shutdown"); thread.setDaemon(false); blockerThread = thread; thread.start(); try { /* Wait for the blocker thread to start. */ mainLock.wait(); } catch (InterruptedException e) { System.err.println("AWT blocker activation interrupted:"); e.printStackTrace(); } } final void registerPeer(final Object target, final Object peer) { synchronized (activationLock) { synchronized (mainLock) { peerMap.put(target, peer); notifyPeerMapUpdated(); } } } final void unregisterPeer(final Object target, final Object peer) { synchronized (activationLock) { synchronized (mainLock) { if (peerMap.get(target) == peer) { peerMap.remove(target); notifyPeerMapUpdated(); } } } } final Object getPeer(final Object target) { synchronized (activationLock) { synchronized (mainLock) { return peerMap.get(target); } } } final void dumpPeers(final PlatformLogger aLog) { if (aLog.isLoggable(PlatformLogger.Level.FINE)) { synchronized (activationLock) { synchronized (mainLock) { aLog.fine("Mapped peers:"); for (Object key : peerMap.keySet()) { aLog.fine(key + "->" + peerMap.get(key)); } } } } } } // class AWTAutoShutdown

Other Java examples (source code examples)

Here is a short list of links related to this Java AWTAutoShutdown.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.