jdk/src/share/classes/java/awt/event/InvocationEvent.java
changeset 4264 40c232605c68
parent 440 a3dac373f62d
child 5506 202f599c92aa
--- a/jdk/src/share/classes/java/awt/event/InvocationEvent.java	Fri Oct 23 14:52:55 2009 +0400
+++ b/jdk/src/share/classes/java/awt/event/InvocationEvent.java	Wed Nov 11 17:46:58 2009 +0300
@@ -78,11 +78,22 @@
 
     /**
      * The (potentially null) Object whose notifyAll() method will be called
-     * immediately after the Runnable.run() method returns.
+     * immediately after the Runnable.run() method has returned or thrown an exception.
+     *
+     * @see #isDispatched
      */
     protected Object notifier;
 
     /**
+     * Indicates whether the <code>run()</code> method of the <code>runnable</code>
+     * was executed or not.
+     *
+     * @see #isDispatched
+     * @since 1.7
+     */
+    private volatile boolean dispatched = false;
+
+    /**
      * Set to true if dispatch() catches Throwable and stores it in the
      * exception instance variable. If false, Throwables are propagated up
      * to the EventDispatchThread's dispatch loop.
@@ -144,7 +155,7 @@
      * source which will execute the runnable's <code>run</code>
      * method when dispatched.  If notifier is non-<code>null</code>,
      * <code>notifyAll()</code> will be called on it
-     * immediately after <code>run</code> returns.
+     * immediately after <code>run</code> has returned or thrown an exception.
      * <p>An invocation of the form <tt>InvocationEvent(source,
      * runnable, notifier, catchThrowables)</tt>
      * behaves in exactly the same way as the invocation of
@@ -159,7 +170,8 @@
      *                          executed
      * @param notifier          The {@code Object} whose <code>notifyAll</code>
      *                          method will be called after
-     *                          <code>Runnable.run</code> has returned
+     *                          <code>Runnable.run</code> has returned or
+     *                          thrown an exception
      * @param catchThrowables   Specifies whether <code>dispatch</code>
      *                          should catch Throwable when executing
      *                          the <code>Runnable</code>'s <code>run</code>
@@ -180,8 +192,8 @@
      * Constructs an <code>InvocationEvent</code> with the specified
      * source and ID which will execute the runnable's <code>run</code>
      * method when dispatched.  If notifier is non-<code>null</code>,
-     * <code>notifyAll</code> will be called on it
-     * immediately after <code>run</code> returns.
+     * <code>notifyAll</code> will be called on it immediately after
+     * <code>run</code> has returned or thrown an exception.
      * <p>This method throws an
      * <code>IllegalArgumentException</code> if <code>source</code>
      * is <code>null</code>.
@@ -195,7 +207,8 @@
      *                          <code>run</code> method will be executed
      * @param notifier          The <code>Object</code> whose <code>notifyAll</code>
      *                          method will be called after
-     *                          <code>Runnable.run</code> has returned
+     *                          <code>Runnable.run</code> has returned or
+     *                          thrown an exception
      * @param catchThrowables   Specifies whether <code>dispatch</code>
      *                          should catch Throwable when executing the
      *                          <code>Runnable</code>'s <code>run</code>
@@ -217,27 +230,33 @@
 
     /**
      * Executes the Runnable's <code>run()</code> method and notifies the
-     * notifier (if any) when <code>run()</code> returns.
+     * notifier (if any) when <code>run()</code> has returned or thrown an exception.
+     *
+     * @see #isDispatched
      */
     public void dispatch() {
-        if (catchExceptions) {
-            try {
+        try {
+            if (catchExceptions) {
+                try {
+                    runnable.run();
+                }
+                catch (Throwable t) {
+                    if (t instanceof Exception) {
+                        exception = (Exception) t;
+                    }
+                    throwable = t;
+                }
+            }
+            else {
                 runnable.run();
             }
-            catch (Throwable t) {
-                if (t instanceof Exception) {
-                    exception = (Exception) t;
+        } finally {
+            dispatched = true;
+
+            if (notifier != null) {
+                synchronized (notifier) {
+                    notifier.notifyAll();
                 }
-                throwable = t;
-            }
-        }
-        else {
-            runnable.run();
-        }
-
-        if (notifier != null) {
-            synchronized (notifier) {
-                notifier.notifyAll();
             }
         }
     }
@@ -278,6 +297,40 @@
     }
 
     /**
+     * Returns {@code true} if the event is dispatched or any exception is
+     * thrown while dispatching, {@code false} otherwise. The method should
+     * be called by a waiting thread that calls the {@code notifier.wait()} method.
+     * Since spurious wakeups are possible (as explained in {@link Object#wait()}),
+     * this method should be used in a waiting loop to ensure that the event
+     * got dispatched:
+     * <pre>
+     *     while (!event.isDispatched()) {
+     *         notifier.wait();
+     *     }
+     * </pre>
+     * If the waiting thread wakes up without dispatching the event,
+     * the {@code isDispatched()} method returns {@code false}, and
+     * the {@code while} loop executes once more, thus, causing
+     * the awakened thread to revert to the waiting mode.
+     * <p>
+     * If the {@code notifier.notifyAll()} happens before the waiting thread
+     * enters the {@code notifier.wait()} method, the {@code while} loop ensures
+     * that the waiting thread will not enter the {@code notifier.wait()} method.
+     * Otherwise, there is no guarantee that the waiting thread will ever be woken
+     * from the wait.
+     *
+     * @return {@code true} if the event has been dispatched, or any exception
+     * has been thrown while dispatching, {@code false} otherwise
+     * @see #dispatch
+     * @see #notifier
+     * @see #catchExceptions
+     * @since 1.7
+     */
+    public boolean isDispatched() {
+        return dispatched;
+    }
+
+    /**
      * Returns a parameter string identifying this event.
      * This method is useful for event-logging and for debugging.
      *