/** * Disposes of this AppContext, all of its top-level Frames, and all Threads and ThreadGroups * contained within it. * * <p>This method must be called from a Thread which is not contained within this AppContext. * * @exception IllegalThreadStateException if the current thread is contained within this * AppContext * @since JDK1.2 */ public void dispose() throws IllegalThreadStateException { // Check to be sure that the current Thread isn't in this AppContext if (this.threadGroup.parentOf(Thread.currentThread().getThreadGroup())) { throw new IllegalThreadStateException( "Current Thread is contained within AppContext to be disposed."); } synchronized (this) { if (this.isDisposed) { return; // If already disposed, bail. } this.isDisposed = true; } // final PropertyChangeSupport changeSupport = this.changeSupport; // if (changeSupport != null) { // changeSupport.firePropertyChange(DISPOSED_PROPERTY_NAME, false, true); // } // First, we post an InvocationEvent to be run on the // EventDispatchThread which disposes of all top-level Frames final Object notificationLock = new Object(); /*no mutiple frames in basis * Runnable runnable = new Runnable() { public void run() { * Frame [] frames = Frame.getFrames(); * for (int i = frames.length - 1; i >= 0; i--) { * frames[i].dispose(); // Dispose of all top-level Frames * } * synchronized(notificationLock) { * notificationLock.notifyAll(); // Notify caller that we're done * } * } }; * synchronized(notificationLock) { * SunToolkit.postEvent(this, * new InvocationEvent(Toolkit.getDefaultToolkit(), runnable)); * try { * notificationLock.wait(DISPOSAL_TIMEOUT); * } catch (InterruptedException e) { } * } */ // Next, we post another InvocationEvent to the end of the // EventQueue. When it's executed, we know we've executed all // events in the queue. Runnable runnable = new Runnable() { public void run() { synchronized (notificationLock) { notificationLock.notifyAll(); // Notify caller that we're done } } }; synchronized (notificationLock) { SunToolkit.postEvent(this, new InvocationEvent(Toolkit.getDefaultToolkit(), runnable)); try { notificationLock.wait(DISPOSAL_TIMEOUT); } catch (InterruptedException e) { } } // Next, we interrupt all Threads in the ThreadGroup this.threadGroup.interrupt(); // Note, the EventDispatchThread we've interrupted may dump an // InterruptedException to the console here. This needs to be // fixed in the EventDispatchThread, not here. // Next, we sleep 10ms at a time, waiting for all of the active // Threads in the ThreadGroup to exit. long startTime = System.currentTimeMillis(); long endTime = startTime + (long) THREAD_INTERRUPT_TIMEOUT; while ((this.threadGroup.activeCount() > 0) && (System.currentTimeMillis() < endTime)) { try { Thread.sleep(10); } catch (InterruptedException e) { } } // Then, we stop any remaining Threads // this.threadGroup.stop(); // Next, we sleep 10ms at a time, waiting for all of the active // Threads in the ThreadGroup to die. startTime = System.currentTimeMillis(); endTime = startTime + (long) THREAD_INTERRUPT_TIMEOUT; while ((this.threadGroup.activeCount() > 0) && (System.currentTimeMillis() < endTime)) { try { Thread.sleep(10); } catch (InterruptedException e) { } } // Next, we remove this and all subThreadGroups from threadGroup2appContext int numSubGroups = this.threadGroup.activeGroupCount(); if (numSubGroups > 0) { ThreadGroup[] subGroups = new ThreadGroup[numSubGroups]; numSubGroups = this.threadGroup.enumerate(subGroups); for (int subGroup = 0; subGroup < numSubGroups; subGroup++) { threadGroup2appContext.remove(subGroups[subGroup]); } } threadGroup2appContext.remove(this.threadGroup); MostRecentThreadAppContext recent = mostRecentThreadAppContext; if ((recent != null) && (recent.appContext == this)) mostRecentThreadAppContext = null; // If the "most recent" points to this, clear it for GC // Finally, we destroy the ThreadGroup entirely. try { this.threadGroup.destroy(); } catch (IllegalThreadStateException e) { // Fired if not all the Threads died, ignore it and proceed } synchronized (table) { this.table.clear(); // Clear out the Hashtable to ease garbage collection } numAppContexts--; mostRecentKeyValue = null; }
/** * Disposes of this AppContext, all of its top-level Frames, and all Threads and ThreadGroups * contained within it. * * <p>This method must be called from a Thread which is not contained within this AppContext. * * @exception IllegalThreadStateException if the current thread is contained within this * AppContext * @since 1.2 */ public void dispose() throws IllegalThreadStateException { // Check to be sure that the current Thread isn't in this AppContext if (this.threadGroup.parentOf(Thread.currentThread().getThreadGroup())) { throw new IllegalThreadStateException( "Current Thread is contained within AppContext to be disposed."); } synchronized (this) { if (this.isDisposed) { return; // If already disposed, bail. } this.isDisposed = true; } final PropertyChangeSupport changeSupport = this.changeSupport; if (changeSupport != null) { changeSupport.firePropertyChange(DISPOSED_PROPERTY_NAME, false, true); } // First, we post an InvocationEvent to be run on the // EventDispatchThread which disposes of all top-level Frames and TrayIcons final Object notificationLock = new Object(); Runnable runnable = new Runnable() { public void run() { Window[] windowsToDispose = Window.getOwnerlessWindows(); for (Window w : windowsToDispose) { w.dispose(); } AccessController.doPrivileged( new PrivilegedAction() { public Object run() { if (!GraphicsEnvironment.isHeadless() && SystemTray.isSupported()) { SystemTray systemTray = SystemTray.getSystemTray(); TrayIcon[] trayIconsToDispose = systemTray.getTrayIcons(); for (TrayIcon ti : trayIconsToDispose) { systemTray.remove(ti); } } return null; } }); // Alert PropertyChangeListeners that the GUI has been disposed. if (changeSupport != null) { changeSupport.firePropertyChange(GUI_DISPOSED, false, true); } synchronized (notificationLock) { notificationLock.notifyAll(); // Notify caller that we're done } } }; synchronized (notificationLock) { SunToolkit.postEvent(this, new InvocationEvent(Toolkit.getDefaultToolkit(), runnable)); try { notificationLock.wait(DISPOSAL_TIMEOUT); } catch (InterruptedException e) { } } // Next, we post another InvocationEvent to the end of the // EventQueue. When it's executed, we know we've executed all // events in the queue. runnable = new Runnable() { public void run() { synchronized (notificationLock) { notificationLock.notifyAll(); // Notify caller that we're done } } }; synchronized (notificationLock) { SunToolkit.postEvent(this, new InvocationEvent(Toolkit.getDefaultToolkit(), runnable)); try { notificationLock.wait(DISPOSAL_TIMEOUT); } catch (InterruptedException e) { } } /* jnode // Next, we interrupt all Threads in the ThreadGroup this.threadGroup.interrupt(); // Note, the EventDispatchThread we've interrupted may dump an // InterruptedException to the console here. This needs to be // fixed in the EventDispatchThread, not here. // Next, we sleep 10ms at a time, waiting for all of the active // Threads in the ThreadGroup to exit. long startTime = System.currentTimeMillis(); long endTime = startTime + (long)THREAD_INTERRUPT_TIMEOUT; while ((this.threadGroup.activeCount() > 0) && (System.currentTimeMillis() < endTime)) { try { Thread.sleep(10); } catch (InterruptedException e) { } } // Then, we stop any remaining Threads this.threadGroup.stop(); // Next, we sleep 10ms at a time, waiting for all of the active // Threads in the ThreadGroup to die. startTime = System.currentTimeMillis(); endTime = startTime + (long)THREAD_INTERRUPT_TIMEOUT; while ((this.threadGroup.activeCount() > 0) && (System.currentTimeMillis() < endTime)) { try { Thread.sleep(10); } catch (InterruptedException e) { } } jnode*/ // Next, we remove this and all subThreadGroups from threadGroup2appContext int numSubGroups = this.threadGroup.activeGroupCount(); if (numSubGroups > 0) { ThreadGroup[] subGroups = new ThreadGroup[numSubGroups]; numSubGroups = this.threadGroup.enumerate(subGroups); for (int subGroup = 0; subGroup < numSubGroups; subGroup++) { threadGroup2appContext.remove(subGroups[subGroup]); } } threadGroup2appContext.remove(this.threadGroup); MostRecentThreadAppContext recent = mostRecentThreadAppContext; if ((recent != null) && (recent.appContext == this)) mostRecentThreadAppContext = null; // If the "most recent" points to this, clear it for GC // Finally, we destroy the ThreadGroup entirely. try { // jnode this.threadGroup.destroy(); } catch (IllegalThreadStateException e) { // Fired if not all the Threads died, ignore it and proceed } synchronized (table) { this.table.clear(); // Clear out the Hashtable to ease garbage collection } numAppContexts--; mostRecentKeyValue = null; }