Interface ThreadPoolFactory

All Known Implementing Classes:
AbstractThreadPoolFactory, DefaultThreadPoolFactory

public interface ThreadPoolFactory

The factory allowing to get a thread pool (ExecutorService) for processing some AlgART array.

The object, implementing this interface, should be used when you need to process some AlgART array ("source array") in several parallel threads to improve performance on the multiprocessor systems. In this case, you should split the algorithm into several tasks, where each task calculates a part of the result (usually processes a region of the source array). Then you need to call getThreadPool(sourceArray, someThreadFactory) method of this object, submit all your tasks to the returned thread pool, wait until all tasks will be completed (for example, by Future.get method) and, at the end, call releaseThreadPool(ExecutorService) method to finish working with the thread pool. The number of tasks, which your algorithm is split into, should be equal to the result of recommendedNumberOfTasks(sourceArray) method of this object. Note: if this number is 1, you should ignore multithreading and perform the task in the current thread.

The technique described above can be automated by performTasks(java.util.concurrent.ThreadFactory, Runnable[]) method.

We recommend to pass some instance of this interface to every algorithm using multithreading technique to optimize performance on multiprocessor computers. Then the application will be able to call algorithms with a custom implementations of this interface, which controls the number of threads and, maybe, supports a global application thread pool. In particular, an instance of this interface can be passed to the standard Arrays.copy(ArrayContext, UpdatableArray, Array) method via the custom implementation of ArrayContext interface.

There is a simple default implementation of this interface: DefaultThreadPoolFactory.

Author:
Daniel Alievsky
  • Method Details

    • recommendedNumberOfTasks

      int recommendedNumberOfTasks()
      Returns the recommended number of tasks, which your algorithm is split into for optimizing processing large data. The returned value can be equal (or depend on) the result of Arrays.SystemSettings.availableProcessors(), or can be specified in some system property or environment variable.

      The returned value is always positive.

      Returns:
      the recommended number of parallel tasks to perform the processing (>0).
    • recommendedNumberOfTasks

      int recommendedNumberOfTasks(Array sourceArray)
      Returns the recommended number of tasks, which your algorithm is split into for optimizing processing the given AlgART on multiprocessor computers. The returned value can be equal (or depend on) the result of Arrays.SystemSettings.availableProcessors(), or can be specified in some system property or environment variable. For little arrays, that are usually processed very quickly, we recommend to return 1 regardless of the number of processors.

      The returned value is always positive.

      Parameters:
      sourceArray - some AlgART array that should be processed.
      Returns:
      the recommended number of parallel tasks to perform the processing (>0).
      Throws:
      NullPointerException - if the argument is null (not necessary).
    • singleThreadVersion

      ThreadPoolFactory singleThreadVersion()
      Returns new factory, identical to this one with the only exception that the recommended number of tasks in the created instance is always one. More precisely, the recommendedNumberOfTasks() and recommendedNumberOfTasks(Array) methods in the created factory always return 1, and all other methods are strictly equivalent to the corresponding methods of this instance.
      Returns:
      the single-thread version of this factory.
    • getThreadPool

      ExecutorService getThreadPool(ThreadFactory threadFactory)
      Returns the thread pool that should be used for multithreading processing large data. Depending on implementation, this method may either create a new thread pool, or return some already existing pool, for example, the global thread pool of the application. In any case, you must call, in a finally section, the releaseThreadPool(ExecutorService) method for this pool after finishing your algorithm.

      The threadFactory can be used for creation new thread pool. This argument may be null: in this case, some default thread factory should be used.

      Parameters:
      threadFactory - if not null, specifies the desired thread factory for using by the thread pool.
      Returns:
      the thread pool for parallel processing large data.
    • getThreadPool

      ExecutorService getThreadPool(Array sourceArray, ThreadFactory threadFactory)
      Returns the thread pool that should be used for multithreading processing an AlgART array. Depending on implementation, this method may either create a new thread pool, or return some already existing pool, for example, the global thread pool of the application. In any case, you must call, in a finally section, the releaseThreadPool(ExecutorService) method for this pool after finishing your algorithm.

      The threadFactory may be used for creation new thread pool. This argument may be null: in this case, some default thread factory should be used.

      Parameters:
      sourceArray - some AlgART array that should be processed.
      threadFactory - if not null, specifies the desired thread factory for using by the thread pool.
      Returns:
      the thread pool for parallel processing the array.
      Throws:
      NullPointerException - if sourceArray argument is null (not necessary).
    • releaseThreadPool

      void releaseThreadPool(ExecutorService pool)
      Finishes using the thread pool returned by getThreadPool(Array, ThreadFactory) method. This method must be called in a finally section after finishing usage of the pool. The reason is that if the implementation of getThreadPool(Array, ThreadFactory) method has created a new thread pool, this method probably calls its shutdown method to remove extra system threads.
      Parameters:
      pool - the thread pool created by the previous getThreadPool(Array, ThreadFactory) call.
      Throws:
      NullPointerException - if the argument is null (not necessary).
    • performTasks

      void performTasks(Runnable[] tasks)
      Equivalent to performTasks(null, tasks) call.
      Parameters:
      tasks - the tasks which should be performed.
      Throws:
      NullPointerException - if tasks argument or one of the tasks is null.
    • performTasks

      void performTasks(ThreadFactory threadFactory, Runnable[] tasks)
      Performs the specified tasks by the thread pool, returned by getThreadPool(threadFactory) method in the beginning of execution.

      More precisely, if tasks.length==0, this method does nothing, if tasks.length==1, this method just calls tasks[0].run(), and if tasks.length>1, the tasks are performed by the following code (where pool is the result of getThreadPool(threadFactory) call):

      
       Future<?>[] results = new Future<?>[tasks.length];
       for (int threadIndex = 0; threadIndex < tasks.length; threadIndex++) {
           results[threadIndex] = pool.submit(tasks[threadIndex]);
       }
       try {
           for (int threadIndex = 0; threadIndex < tasks.length; threadIndex++) {
               results[threadIndex].get(); // waiting for finishing
           }
       } catch (ExecutionException ex) {
           Throwable cause = ex.getCause();
           if (cause instanceof RuntimeException)
               throw (RuntimeException)cause;
           if (cause instanceof Error)
               throw (Error)cause;
           throw new AssertionError("Unexpected checked exception: " + cause);
           // it is impossible, because run() method in tasks does not declare any exceptions
       } catch (InterruptedException ex) {
           throw new java.io.IOError(ex);
       }
       

      Before finishing, this method calls releaseThreadPool(java.util.concurrent.ExecutorService) method for the used pool (in finally section).

      As you see, if java.util.concurrent.ExecutionException is thrown while calling one of results[...].get(), this exception is caught, and this method throws the result of its getCause() method. In other words, all possible exceptions while performing tasks are thrown as if they would be performed in the current thread.

      If java.lang.InterruptedException is thrown while calling one of results[...].get(), this exception is also caught, and this method throws java.io.IOError. (In Java 1.5, which does not support java.io.IOError, the similar net.algart.arrays.IOErrorJ5 exception is thrown instead: this branch is not listed above.) Usually, you should avoid interrupting the threads, processing AlgART arrays, via Thread.interrupt() technique (which leads to java.lang.InterruptedException): see the package description about runtime exceptions issue.

      Parameters:
      threadFactory - the factory, passed to getThreadPool(java.util.concurrent.ThreadFactory) method to get the necessary thread pool; may be null, then some default thread factory will be used.
      tasks - the tasks which should be performed.
      Throws:
      NullPointerException - if tasks argument or one of the tasks is null.
      See Also:
    • performTasks

      void performTasks(Array sourceArray, ThreadFactory threadFactory, Runnable[] tasks)
      Equivalent to performTasks(java.util.concurrent.ThreadFactory, Runnable[]) method with the only difference, that the thread pool is got via getThreadPool(sourceArray, threadFactory) method.
      Parameters:
      sourceArray - the AlgART array, passed to getThreadPool(Array, java.util.concurrent.ThreadFactory) method to get the necessary thread pool.
      threadFactory - the factory, passed to getThreadPool(Array, java.util.concurrent.ThreadFactory) method to get the necessary thread pool; may be null, then some default thread factory will be used.
      tasks - the tasks which should be performed.
      Throws:
      NullPointerException - if tasks argument or one of the tasks is null.
    • performTasks

      void performTasks(Runnable[] tasks, int from, int to)
      Equivalent to performTasks(java.util.Arrays.copyOfRange(tasks, from, to)) call.
      Parameters:
      tasks - the tasks which should be performed.
      from - the initial index of the performed task, inclusive
      to - the final index of the performed task, exclusive. (This index may lie outside the array.)
      Throws:
      NullPointerException - if tasks argument or one of tasks in the specified range is null.
      IndexOutOfBoundsException - if from < 0 or from > tasks.length.
      IllegalArgumentException - if from > to.
    • performTasks

      void performTasks(ThreadFactory threadFactory, Runnable[] tasks, int from, int to)
      Equivalent to performTasks(threadFactory, java.util.Arrays.copyOfRange(tasks, from, to)) call.
      Parameters:
      tasks - the tasks which should be performed.
      from - the initial index of the performed task, inclusive
      to - the final index of the performed task, exclusive. (This index may lie outside the array.)
      Throws:
      NullPointerException - if tasks argument or or one of tasks in the specified range is null.
      IndexOutOfBoundsException - if from < 0 or from > tasks.length.
      IllegalArgumentException - if from > to.