Class TestThreadsHolder<T extends java.lang.Runnable>

  • All Implemented Interfaces:
    RunnerCreator<java.lang.Runnable>

    public class TestThreadsHolder<T extends java.lang.Runnable>
    extends java.lang.Object
    implements RunnerCreator<java.lang.Runnable>
    Allows to let any number of threads start at the same time by starting them up and (internally) waiting until all of them are up and running. This is especially useful when larger numbers of threads are being created for testing purpose because otherwise often creation time outnumbers shorter testing time which at worst would make a parallel test run nearly single threaded.

    Also this class provides means to either wait for test threads to finish or to stop them manually via Thread.interrupt().

    • Constructor Summary

      Constructors 
      Constructor Description
      TestThreadsHolder​(int numberOfThreads)
      Creates a specified number of threads that will perform the given runnable logic as soon as startAll() has been invoked.
      TestThreadsHolder​(int numberOfThreads, boolean inheritTenant)
      Creates a specified number of threads that will perform the given runnable logic as soon as startAll() has been invoked.
      TestThreadsHolder​(int numberOfThreads, RunnerCreator<T> creator)
      Creates a specified number of threads that will perform the logic created by the specified runnable creator as soon as startAll() has been invoked.
      TestThreadsHolder​(int numberOfThreads, RunnerCreator<T> creator, boolean inheritTenant)
      Creates a specified number of threads that will perform the logic created by the specified runnable creator as soon as startAll() has been invoked.
      TestThreadsHolder​(int numberOfThreads, T runnable)
      Creates a specified number of threads that will perform the given runnable logic as soon as startAll() has been invoked.
      TestThreadsHolder​(int numberOfThreads, T runnable, boolean inheritTenant)
      Creates a specified number of threads that will perform the given runnable logic as soon as startAll() has been invoked.
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      int getAlive()
      Returns the current number of threads that did not complete their testing logic.
      java.util.Map<java.lang.Integer,​java.lang.Throwable> getErrors()
      Returns all errors recorded from runner threads.
      T getRunner​(int pos)  
      java.util.List<T> getRunners()  
      long getStartToFinishMillis()
      If all threads finished in
      boolean hasErrors()
      Tells whether any runner has recorded a error.
      java.lang.Runnable newRunner​(int threadNumber)
      Creates a new runnable object for the given runner thread number.
      boolean runAll​(long duration, java.util.concurrent.TimeUnit unit, int stopWaitSeconds)
      Starts all threads via startAll() and lets them run for the specified duration.
      void startAll()
      Allows all runner threads to perform the given test logic.
      void stopAll()
      Stops all runner threads by invoking Thread.interrupt().
      boolean stopAndDestroy​(int timeWaitSeconds)
      Attempts to stop all runners via stopAll() and waits for completion for 10 seconds.
      protected boolean useBusyWaiting()
      Override to change latch timeout guarded waiting method.
      boolean waitAndDestroy​(int terminationWaitSeconds)
      Waits for runner termination for the specified time.
      boolean waitForAll​(long timeout, java.util.concurrent.TimeUnit unit)
      Waits for all runners to finish their work for a specified amount of time.
      boolean waitForPrepared​(long timeout, java.util.concurrent.TimeUnit unit)  
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Constructor Detail

      • TestThreadsHolder

        public TestThreadsHolder​(int numberOfThreads)
        Creates a specified number of threads that will perform the given runnable logic as soon as startAll() has been invoked. Please note that this constructor is intended for creating inner classes only. The newRunner(int) method of this inner class *must* be overwritten!
      • TestThreadsHolder

        public TestThreadsHolder​(int numberOfThreads,
                                 boolean inheritTenant)
        Creates a specified number of threads that will perform the given runnable logic as soon as startAll() has been invoked. Please note that this constructor is intended for creating inner classes only. The newRunner(int) method of this inner class *must* be overwritten!
      • TestThreadsHolder

        public TestThreadsHolder​(int numberOfThreads,
                                 T runnable)
        Creates a specified number of threads that will perform the given runnable logic as soon as startAll() has been invoked.

        Please note that technically the actual threads will be immediately created and started. Calling startAll() only releases them from a waiting state.

        Parameters:
        numberOfThreads - the number of runner threads to use
        runnable - the runnable instance being used by each runner thread
      • TestThreadsHolder

        public TestThreadsHolder​(int numberOfThreads,
                                 T runnable,
                                 boolean inheritTenant)
        Creates a specified number of threads that will perform the given runnable logic as soon as startAll() has been invoked.

        Please note that technically the actual threads will be immediately created and started. Calling startAll() only releases them from a waiting state.

        Parameters:
        numberOfThreads - the number of runner threads to use
        runnable - the runnable instance being used by each runner thread
        inheritTenant - if true all runner threads will inherit the current callers tenant, if false no thread will have a active tenant
      • TestThreadsHolder

        public TestThreadsHolder​(int numberOfThreads,
                                 RunnerCreator<T> creator)
        Creates a specified number of threads that will perform the logic created by the specified runnable creator as soon as startAll() has been invoked.

        Please note that technically the actual threads will be immediately created and started. Calling startAll() only releases them from a waiting state.

        Parameters:
        numberOfThreads - the number of runner threads to use
        creator - the creator responsible for providing a runnable instance for each runner thread
      • TestThreadsHolder

        public TestThreadsHolder​(int numberOfThreads,
                                 RunnerCreator<T> creator,
                                 boolean inheritTenant)
        Creates a specified number of threads that will perform the logic created by the specified runnable creator as soon as startAll() has been invoked.

        Please note that technically the actual threads will be immediately created and started. Calling startAll() only releases them from a waiting state.

        Parameters:
        numberOfThreads - the number of runner threads to use
        creator - the creator responsible for providing a runnable instance for each runner thread
        inheritTenant - if true each runner thread will inherit the current callers tenant, if false all threads will have no active tenant set
    • Method Detail

      • useBusyWaiting

        protected boolean useBusyWaiting()
        Override to change latch timeout guarded waiting method.

        As default waiting is done via CountDownLatch.await(long, TimeUnit) which is most efficient for not disturbing workers and returning as quick as possible.

        However if you're suffering from JVM being blocked often (not getting computing time for minutes) for instance when running in a virtual environment it may be better to change timeout method to busily counting 'ticks'. In that case the latch is tested many times waiting at most one second. In case the JVM is being blocked for a longer time the timeout mechanism simply continues where it was blocked giving workers a fair chance to finished their work, even if it means that the actual timeout period is greatly exceeded!

      • newRunner

        public java.lang.Runnable newRunner​(int threadNumber)
        Description copied from interface: RunnerCreator
        Creates a new runnable object for the given runner thread number.
        Specified by:
        newRunner in interface RunnerCreator<T extends java.lang.Runnable>
      • waitForPrepared

        public boolean waitForPrepared​(long timeout,
                                       java.util.concurrent.TimeUnit unit)
      • startAll

        public void startAll()
        Allows all runner threads to perform the given test logic. Ensures that all threads are up and running, which means that thread creation and startup overhead does not affect the tested logic at all.

        You may either wait for them to terminate on their own by calling waitForAll(long, TimeUnit) or stop them after some time via stopAll()

        See Also:
        stopAll(), waitForAll(long, TimeUnit)
      • runAll

        public boolean runAll​(long duration,
                              java.util.concurrent.TimeUnit unit,
                              int stopWaitSeconds)
        Starts all threads via startAll() and lets them run for the specified duration.

        After that all threads are stopped via stopAndDestroy(int) and the stop result is being returned.

        Parameters:
        duration - the time to run
        unit - the unit of time to run
        stopWaitSeconds - the time to wait after stopping threads before killing them 'the hard way'
      • stopAll

        public void stopAll()
        Stops all runner threads by invoking Thread.interrupt(). Please make sure that the tested logic is handling thread interrupts correctly, which means either to pass on the InterruptedException or restoring the interrupted flag via Thread.interrupt()!
      • stopAndDestroy

        public boolean stopAndDestroy​(int timeWaitSeconds)
        Attempts to stop all runners via stopAll() and waits for completion for 10 seconds. If for some reason this doesn't work it will unsafely stop all runners via Thread.stop().
        Returns:
        true in case all runners finished orderly, false otherwise
      • waitAndDestroy

        public boolean waitAndDestroy​(int terminationWaitSeconds)
        Waits for runner termination for the specified time. If for some reason this doesn't work it will first try to stop them via interrupt, wait for terminationWaitSeconds/2 and only if this doesn't succeed all remaining workers will be unsafely stopped via Thread.stop().
        Parameters:
        terminationWaitSeconds - the time to wait for runner thread termination in seconds; after this time has elapsed it will unsafely kill them via Thread.stop()
      • getStartToFinishMillis

        public long getStartToFinishMillis()
        If all threads finished in
      • getAlive

        public int getAlive()
        Returns the current number of threads that did not complete their testing logic.

        Technically more threads than the returned number may be still alive, but as soon as they have completed their 'payload' they will definitely terminate so there is no need to wait for that.

      • waitForAll

        public boolean waitForAll​(long timeout,
                                  java.util.concurrent.TimeUnit unit)
        Waits for all runners to finish their work for a specified amount of time.
        Returns:
        true in case all runners did really finish, false otherwise
      • hasErrors

        public boolean hasErrors()
        Tells whether any runner has recorded a error.
        See Also:
        getErrors()
      • getErrors

        public java.util.Map<java.lang.Integer,​java.lang.Throwable> getErrors()
        Returns all errors recorded from runner threads.

        Please note that InterruptedException will not be recorded since this we prefer thread interrupt as valid way of stopping runners.

        See Also:
        hasErrors()
      • getRunners

        public java.util.List<T> getRunners()
      • getRunner

        public T getRunner​(int pos)