Class Completed


  • public class Completed
    extends java.lang.Object
    Completed - Documentation.

    This class helps a Thread wait for the situation where all Thread's that have 'registered' with this class have reported 'finished' messages. This class offers two wait methods that will halt progress on the current Thread until all registered Thread's have reported a 'finished' message.

    It is important to note, that the reporting of an exception is not sufficient messaging for informing an instance of 'Completed' that a Thread has run to completion. Rather, if the invoking thread has the ability to tell this class that exceptions have occurred, it should also have the ability to report when it consider Thread progress to have run to termination. This means that if writing a try-catch block, inside the catch an invocation of Completed.exceptionWasThrown should be followed by a finally block that relays that the method or thread has completed it's work.

    When an instance of this class 'Completed' has been told to wait, the invoking Thread will not proceed until all the registered Thread's have reported a 'finished' message (by using the 'finished' method).




    • Method Detail

      • finalize

        protected void finalize()
        Makes sure the Thread's are cleared out of the internal-storage Vector's
        Overrides:
        finalize in class java.lang.Object
        Code:
        Exact Method Body:
        1
        2
        3
         watchedThreads.clear(); watchedThreads  = null;
         exceptions.clear();     exceptions      = null;
         finished.clear();       finished        = null;
        
      • find

        protected int find​(java.lang.Thread thread)
        Provided a given input Thread parameter, this method the index-location in the in the internal-storage Vector's of that Thread.
        Parameters:
        thread - This may be any Java Thread instance, but only ones which have earlier been registered with this Completed instance will be found in the internal-storage.
        Returns:
        Returns the index of the internal-storage Vector's for the provided Thread.
        Code:
        Exact Method Body:
        1
        2
        3
        4
        5
         for (int i=0; i < watchedThreads.size(); i++)
             if (thread == watchedThreads.elementAt(i))
                 return i;
        
         return -1;
        
      • clear

        public void clear()
        Fully resets the internal state of this instance of Completed. The behavior of this instance would be identical as if it has just been created by a constructor.
        Code:
        Exact Method Body:
        1
        2
        3
        4
         watchedThreads.clear();
         exceptions.clear();
         finished.clear();
         waitHasBeenCalled = false;
        
      • reset

        public void reset()
        This takes this instance of 'Completed' and removes any registered exceptions and the any responses that this instance has received from the Thread's themselves. This method does not remove the registered Thread's. This differs from the behavior of the method clear() which also removes the registered Thread's.
        Code:
        Exact Method Body:
        1
        2
         for (int i=0; i < exceptions.size(); i++) exceptions.setElementAt(null, i);
         for (int i=0; i < finished.size(); i++) finished.setElementAt(Boolean.FALSE, i);
        
      • nameAndId

        public static java.lang.String nameAndId​(java.lang.Thread thread)
        Converts a java.lang.Thread to a String using it's name and id fields.
        Parameters:
        thread - This may be any java thread
        Returns:
        a Java String that contains the values in Thread.getID() and also Thread.getName(). If Thread.getName() returns null, then the name printed will simply be "Name Not Available"
        Code:
        Exact Method Body:
        1
        2
         return "Thread [ID: " + thread.getId() + ", Name: " +
             ((thread.getName() != null) ? thread.getName() : "Name Not Available") + "]";
        
      • addThread

        public void addThread​(java.lang.Thread thread)
        This monitor class will accept 'finished' and 'exceptionWasThrown' messages (invocations) from the Thread that is passed as a parameter to this method, 'addThread'.
        Parameters:
        thread - This may be any Java Thread. This thread will be registered with this class. Registering allows Thread's to send 'finished' messages to this monitor class (by-way-of calling this class Completed.finished method.
        Throws:
        java.lang.IllegalArgumentException - If the 'thread' parameter instance has already been registered with this instance of 'Completed' (using this addThread(Thread) method, then IllegalArgumentException will throw.
        java.lang.IllegalThreadStateException - If an attempt is made to add a Thread to this instance of Completed (using this method, Completed.addThread), *after* a call to one of the Completed.waitForCompletion... methods have been invoked. Once a call to a wait method has been made, new Thread's to monitor cannot be added using this method until all previously added thread's have sent 'finished' messages, and a call to either clear() or reset() has been made.
        Code:
        Exact Method Body:
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
         if (find(thread) != -1) throw new IllegalArgumentException(
             "This " + nameAndId(thread) + " has already been added to this instance of " +
             "class 'Completed'."
         );
        
         if (waitHasBeenCalled) throw new IllegalThreadStateException(
             "This instance of Completed has already been issued a waitForCompletion... method " +
             "invocation, and is not currently accepting new Thread's to add to it's internal " +
             "list of threads to wait on.  In order for class Completed to wait for a thread to " +
             "finish, that thread must be registered with this instance (using this method " +
             "'addThread') *BEFORE* a call to waitForCompletion is made."
         );
        
         watchedThreads.add(thread);
         exceptions.add(null);
         finished.add(Boolean.FALSE);
        
      • exceptionWasThrown

        public boolean exceptionWasThrown​(java.lang.Thread thread,
                                          java.lang.Exception exception)
        This method may be invoked to tell this instance of Completed that a particular Thread has thrown an Exception. The thrown 'exception' will be recorded, and may even be retrieved later (or thrown), if needed.

        Internally, the Exception will be stored and associated with the 'thread' parameter.

        IMPORTANT: Even after an 'exception throw' message is sent to an instance of this class (using this method, 'Completed.exceptionWasThrown'), Completed will still wait for the Thread that registered this exception to finish. Regardless of reported-exceptions, it is always necessary to send 'finished' messages to this class (using method 'Completed.finished') for each Thread that this instance is waiting on.
        Parameters:
        thread - This is the Thread that has thrown the 'exception'
        exception - This is the Exception that was thrown.
        Returns:
        This method will return TRUE, unless the 'thread' parameter has already had an exception reported about it. It is neither mandatory nor critical to heed this return-value. It just reports whether this is the first 'Exception' reported about the 'thread' parameter.
        Throws:
        java.lang.IllegalStateException - This exception throws if this instance of 'Completed' has not received a call to one of the waitForCompletion... methods already. Reporting that one of the Thread's on which this class is "waiting for Completion" has thrown an exception, without first telling this instance to wait will cause IllegalStateException.
        java.lang.IllegalArgumentException - This exception throws if the 'thread' parameter was not actually registered with this instance of 'Completed'. In order for an instance of Completed to heed either 'finished' or 'exception' messages from a Thread, that Thread must first have been registered with the instance using the addThread(Thread) method.
        See Also:
        addThread(Thread), find(Thread), exceptions
        Code:
        Exact Method Body:
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
         if (! waitHasBeenCalled) throw new IllegalStateException(
             "An 'exception-throw' message has been sent to this instance of Completed by " +
             nameAndId(thread) + ", but unfortunately, no invocations of 'wait' have been issued " +
             "to this class yet.  Exception-throw messages (which are explicitly sent by calling " +
             "this method, 'exceptionWasThrown') CANNOT be sent until one of the " +
             "'waitForCompletion...' methods have been invoked."
         );
        
         int pos = find(thread);
        
         if (pos == -1) throw new IllegalArgumentException(
             "The " + nameAndId(thread) + ", for which this this method 'exceptionWasThrown' " +
             "was invoked has not been registered with this instance of 'Completed' (using the " +
             "Completed.addThread(...) method prior to the calling 'exceptionWasThrown'."
         );
        
         boolean ret = exceptions.elementAt(pos) == null;
         exceptions.setElementAt(exception, pos);
         return ret;
        
      • finished

        public void finished​(java.lang.Thread thread)
        Informs this 'Completed' class instance that the 'thread' instance has run to completion. Attempts to wake up the monitor Thread running this instance of Completed using this.notify() to check if all Thread's that are being monitored have completed
        Parameters:
        thread - This is the Thread that has completed it's task.
        Throws:
        java.lang.IllegalStateException - This exception throws if this instance of 'Completed' has not received a call to one of the waitForCompletion... methods already. Reporting that one of the Thread's on which this class is "waiting for Completion" has finished, without first telling this instance to wait will cause IllegalStateException.
        java.lang.IllegalArgumentException - This exception throws if the 'thread' parameter was not actually registered with this instance of 'Completed'. In order for an instance of Completed to heed either 'finished' or 'exception' messages from a Thread, that Thread must first have been registered with the instance using the Completed.addThread(Thread) method.
        java.lang.IllegalThreadStateException - If a second finished message is sent for a particular registered-Thread (as in registered earlier through the addThread method) then this exception will throw. Unless calls to either reset() or clear() are made, multiple invocations of 'finished' cannot be made using the exact same Thread parameter.
        See Also:
        addThread(Thread), find(Thread), finished
        Code:
        Exact Method Body:
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
         if (! waitHasBeenCalled) throw new IllegalStateException(
             "A 'finished' message has been sent to this instance of Completed by " +
             nameAndId(thread) + ", but unfortunately, no invocations of 'wait' have been issued " +
             "to this class yet.  Finished messages (which are explicitly sent by calling this " +
             "method, 'finished') CANNOT be sent until one of the 'waitForCompletion...' methods " +
             "have been invoked."
         );
        
         int pos = find(thread);
        
         if (pos == -1) throw new IllegalArgumentException(
             "The " + nameAndId(thread) + " for which this this method 'finished' was invoked " +
             "was not not registered using this class 'addThread' method prior to calling " + 
             "'finished'"
         );
        
         if (finished.elementAt(pos) == Boolean.TRUE) throw new IllegalThreadStateException(
             "A 'finished' message has already been sent by " + nameAndId(thread) + " to this " +
             "instance of Complete.  This instance must be issued a 'clear' or 'reset' " +
             "message (by calling methods with these names) first before reporting that this " +
             "Thread has finished again."
         );
        
         finished.setElementAt(Boolean.TRUE, pos);
        
         // THE NOTIFY IS DONE HERE
         this.notify();
        
      • waitForCompletionOfAllThreads

        public void waitForCompletionOfAllThreads()
                                           throws java.lang.InterruptedException
        This method shall:

        1. First, this method checks whether all registered Thread's (which must have been registered using the addThread(Thread) method) have already reported 'finished' messages using the method finished(Thread). If all registered Thread's have finished, this method shall exit gracefully.
        2. Next, if there are registered Thread's that have not completed, then this method shall make a call to this.wait(), and halt the current Thread's progress until 'this' instance receives a notify() call from the JVM's Object.notify() mechanism. It is important to note that when any other method calls this class' 'finished(Thread)' method, the code in this class will call this.notify() and wake up any other dormant or 'sleeping' Thread's. When all Thread's have reported 'finished(Thread)' then and only then shall this method shall exit. If there are other threads that need to complete, then this method will invoked this.wait() until they have.
        Throws:
        java.lang.IllegalStateException - If this method is invoked, but no Thread's have been registered with this instance of 'Completed' (using the Completed.addThread method), then this exception will throw. This is because there would be nothing for this method to do, as in this case there would be no registered Thread's to wait on.
        java.lang.IllegalThreadStateException - If this instance of completed has already been asked to 'wait' for thread completion, then this exception shall throw. A 'wait' message should only be invoked on an instance of Completed once. Note that both the reset() and the clear() methods shall reset this instance flag regarding whether a 'wait' request has already been issued.
        If - the JVM internal process is interrupted by some other Thread then an InterruptedException will throw.
        java.lang.InterruptedException
        Code:
        Exact Method Body:
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
         if (watchedThreads.size() == 0) throw new IllegalStateException(
             "This instance of Complete has not received any calls to its 'addThread' method, " +
             "and therefore does not have any Thread's to wait on for completion."
         );
        
         if (waitHasBeenCalled) throw new IllegalThreadStateException(
             "A 'wait' method has already been invoked on this class.  'reset' or 'clear' must " +
             "be invoked, or a new instance of Completed must be created before calling any " +
             "more 'waitForCompletion...' methods."
         );
        
         waitHasBeenCalled = true;
        
         for (Thread thread : watchedThreads) thread.start();
        
         while (true)
         {
             boolean allThreadsHaveFinished = true;
        
             HERE:
             for (Boolean threadIsFinished : finished)
                 if (! threadIsFinished.booleanValue())
                 { allThreadsHaveFinished = false; break HERE; }
        
             if (allThreadsHaveFinished) return;
             else                        this.wait();
         }
        
      • waitForCompletionOf

        public void waitForCompletionOf​(java.lang.Thread... threads)
                                 throws java.lang.InterruptedException
        This method shall:

        1. First, this method checks whether the Thread's which are listed by parameter 'threads' (each of which must have registered using the addThread(Thread) method) have already reported 'finished' messages using the method finished(Thread). If every Thread listed by Varargs parameter 'threads' has finished, then this method shall simply exit gracefully.
        2. Next, if some of the Thread's listed in parameter 'threads' have not completed, then this method shall make a call to this.wait(), and halt the current Thread's progress until 'this' instance receives a notify() call from the JVM's Object.notify() mechanism. It is important to note that when any other method calls this class' 'finished(Thread)' method, the code in this class will call this.notify() and wake up any other dormant or 'sleeping' Thread's that are using 'this' object as a waiting-lock. When all Thread's listed as input have reported 'finished(Thread)' - then and and only then shall this method exit. When 'this' instance receives a JVM notify() message, if there are other Thread's that still need to complete, then this method shall invoke this.wait() again (until all listed Thread's have completed).
        Parameters:
        threads - This Varargs parameter shall take a list of Thread's for this instance of Completed to check-on and wait-for completion. It is important to note that the Thread's in this parameter must have been registered with this class (using the addThread(Thread) method, or else an IllegalArgumentException shall throw.
        Throws:
        java.lang.IllegalStateException - If this method is invoked, but no Thread's have been registered with this instance of 'Completed' (using the Completed.addThread method), then this exception will throw. This is because there would be nothing for this method to do, as in this case there would be no registered Thread's to wait on.
        java.lang.IllegalThreadStateException - If this instance of completed has already been asked to 'wait' for thread completion, then this exception shall throw. A 'wait' message should only be invoked on an instance of Completed once. Note that both the reset() and the clear() methods shall reset this instance flag regarding whether a 'wait' request has already been issued.
        java.lang.IllegalArgumentException - If any of the Thread's listed in Varargs parameter 'threads' were not added to this class using the addThread(Thread) method, then an IllegalArgumentException will throw.
        java.lang.NullPointerException - if any of the 'threads' passed to the Varargs parameter are null references.
        If - the JVM internal process is interrupted by some other Thread then an InterruptedException will throw.
        java.lang.InterruptedException
        Code:
        Exact Method Body:
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
         if (watchedThreads.size() == 0) throw new IllegalStateException(
             "This instance of Complete has not received any calls to its 'addThread' method, " +
             "and therefore does not have any Thread's to wait on for completion."
         );
        
         if (waitHasBeenCalled) throw new IllegalThreadStateException(
             "A 'wait' method has already been invoked on this class.  'reset' must be " +
             "invoked, or a new instance of Completed must be created"
         );
        
         int[] posArr = new int[threads.length];
        
         for (int i=0; i < threads.length; i++)
         {
             if (threads[i] == null) throw new NullPointerException(
                 "The " + i + StringParse.ordinalIndicator(i) + " element of the input Thread-" +
                 "Array was null"
             );
        
             posArr[i] = find(threads[i]);
        
             if (posArr[i] == -1) throw new IllegalArgumentException(
                 "One of the threads passed to this method was never registered using the " +
                 "'addThread' method."
             );
         }
        
         waitHasBeenCalled = true;
        
         for (int threadIndex : posArr) watchedThreads.elementAt(threadIndex).start();
        
         while (true)
         {
             boolean allThreadsHaveFinished = true;
        
             HERE:
             for (int pos : posArr)
                 if (! finished.elementAt(pos).booleanValue()) 
                 { allThreadsHaveFinished = false; break HERE; }
        
             if (allThreadsHaveFinished) return;
             else                        this.wait();
         }
        
      • ifExceptionThrowException

        public void ifExceptionThrowException()
        This method throws a wrapper-Exception (CompletionException) that wraps any Exceptions which were thrown by the other Thread's which have added themselves to this class - and reported those exceptions to this instance
        Throws:
        java.util.concurrent.CompletionException - An 'unchecked' Exception (inherits from class java.lang.RuntimeException) which wraps any exception thrown that has been reported by the Thread's registered with this instance.
        Code:
        Exact Method Body:
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
         int pos=0;
        
         while (pos < exceptions.size())
             if (exceptions.elementAt(pos) != null) break;
             else pos++;
        
         if (pos == exceptions.size()) return;
        
         Thread thread      = watchedThreads.elementAt(pos);
         String name        = thread.getName();
         String description = "Thread ID: [" + thread.getId() + "]";
        
         if (name != null) description += ", Thread Name: [" + name + "]";
        
         for (Exception e : exceptions) if (e != null) throw new CompletionException(
             "There was an exception when attempting to execute this command.  Please see this " +
             "exception's 'Throwable.getCause()' method for more details." + description, e
         );