| 
 | |||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | ||||||||
java.lang.Objectorg.logicalcobwebs.concurrent.FJTaskRunnerGroup
public class FJTaskRunnerGroup
A stripped down analog of a ThreadGroup used for establishing and managing FJTaskRunner threads. ThreadRunnerGroups serve as the control boundary separating the general world of normal threads from the specialized world of FJTasks.
By intent, this class does not subclass java.lang.ThreadGroup, and does not support most methods found in ThreadGroups, since they would make no sense for FJTaskRunner threads. In fact, the class does not deal with ThreadGroups at all. If you want to restrict a FJTaskRunnerGroup to a particular ThreadGroup, you can create it from within that ThreadGroup.
The main contextual parameter for a FJTaskRunnerGroup is the group size, established in the constructor. Groups must be of a fixed size. There is no way to dynamically increase or decrease the number of threads in an existing group.
 In general, the group size should be equal to the number
 of CPUs on the system. (Unfortunately, there is no portable
 means of automatically detecting the number of CPUs on a JVM, so there is
 no good way to automate defaults.)  In principle, when
 FJTasks are used for computation-intensive tasks, having only
 as many threads as CPUs should minimize bookkeeping overhead
 and contention, and so maximize throughput. However, because
 FJTaskRunners lie atop Java threads, and in turn operating system
 thread support and scheduling policies,
 it is very possible that using more threads
 than CPUs will improve overall throughput even though it adds
 to overhead. This will always be so if FJTasks are I/O bound.
 So it may pay to experiment a bit when tuning on particular platforms.
 You can also use setRunPriorities to either
 increase or decrease the priorities of active threads, which
 may interact with group size choice.
 
In any case, overestimating group sizes never seriously degrades performance (at least within reasonable bounds). You can also use a value less than the number of CPUs in order to reserve processing for unrelated threads.
There are two general styles for using a FJTaskRunnerGroup. You can create one group per entire program execution, for example as a static singleton, and use it for all parallel tasks:
 class Tasks {
   static FJTaskRunnerGroup group;
   public void initialize(int groupsize) {
      group = new FJTaskRunnerGroup(groupSize);
   }
   // ...
 }
 
 Alternatively, you can make new groups on the fly and use them only for
 particular task sets. This is more flexible,,
 and leads to more controllable and deterministic execution patterns,
 but it encounters greater overhead on startup. Also, to reclaim
 system resources, you should
 call FJTaskRunnerGroup.interruptAll when you are done
 using one-shot groups. Otherwise, because FJTaskRunners set
 Thread.isDaemon
 status, they will not normally be reclaimed until program termination.
 
 The main supported methods are execute,
 which starts a task processed by FJTaskRunner threads,
 and invoke, which starts one and waits for completion.
 For example, you might extend the above FJTasks
 class to support a task-based computation, say, the
 Fib class from the FJTask documentation:
 
 class Tasks { // continued
   // ...
   static int fib(int n) {
     try {
       Fib f = new Fib(n);
       group.invoke(f);
       return f.getAnswer();
     }
     catch (InterruptedException ex) {
       throw new Error("Interrupted during computation");
     }
   }
 }
 
 
 Method stats() can be used to monitor performance.
 Both FJTaskRunnerGroup and FJTaskRunner may be compiled with
 the compile-time constant COLLECT_STATS set to false. In this
 case, various simple counts reported in stats() are not collected.
 On platforms tested,
 this leads to such a tiny performance improvement that there is
 very little motivation to bother.
 
[ Introduction to this package. ]
FJTaskRunnerGroup.InvokableFJTask, 
FJTaskRunner| Nested Class Summary | |
|---|---|
| protected static class | FJTaskRunnerGroup.InvokableFJTaskWrap wait/notify mechanics around a task so that invoke() can wait it out | 
| Field Summary | |
|---|---|
| protected  int | activeCountNumber of threads that are not waiting for work | 
| (package private) static boolean | COLLECT_STATSCompile-time constant. | 
| (package private) static int | DEFAULT_SCAN_PRIORITY | 
| (package private)  int | entriesTotal number of executes or invokes | 
| protected  LinkedQueue | entryQueueGroup-wide queue for tasks entered via execute() | 
| (package private)  long | initTimeThe time at which this ThreadRunnerGroup was constructed | 
| (package private) static long | MAX_SLEEP_TIMEThe maximum time (in msecs) to sleep when a thread is idle, yet others are not, so may eventually generate work that the current thread can steal. | 
| protected  int | nstartedNumber of threads that have been started. | 
| (package private) static long | SCANS_PER_SLEEPThe number of times to scan other threads for tasks before transitioning to a mode where scans are interleaved with sleeps (actually timed waits). | 
| protected  FJTaskRunner[] | threadsThe threads in this group | 
| Constructor Summary | |
|---|---|
| FJTaskRunnerGroup(int groupSize)Create a FJTaskRunnerGroup with the indicated number of FJTaskRunner threads. | |
| Method Summary | |
|---|---|
| protected  void | checkActive(FJTaskRunner t,
            long scans)Set active status of thread t to false, and then wait until: (a) there is a task in the entry queue, or (b) other threads are active, or (c) the current thread is interrupted. | 
|  void | execute(java.lang.Runnable r)Arrange for execution of the given task by placing it in a work queue. | 
|  void | executeTask(FJTask t)Specialized form of execute called only from within FJTasks | 
| protected  boolean | getActive(FJTaskRunner t)Return active status of t. | 
|  int | getActiveCount()Return the number of threads that are not idly waiting for work. | 
| protected  FJTaskRunner[] | getArray()Return the array of threads in this group. | 
| protected  void | initializeThreads()Create all FJTaskRunner threads in this group. | 
|  void | interruptAll()Try to shut down all FJTaskRunner threads in this group by interrupting them all. | 
|  void | invoke(java.lang.Runnable r)Start a task and wait it out. | 
| protected  FJTask | pollEntryQueue()Return a task from entry queue, or null if empty. | 
| protected  void | setActive(FJTaskRunner t)Set active status of thread t to true, and notify others that might be waiting for work. | 
| protected  void | setInactive(FJTaskRunner t)Set active status of thread t to false. | 
|  void | setRunPriorities(int pri)Set the priority to use while a FJTaskRunner is actively running tasks. | 
|  void | setScanPriorities(int pri)Set the priority to use while a FJTaskRunner is polling for new tasks to perform. | 
| protected  void | signalNewTask()Start or wake up any threads waiting for work | 
|  int | size()Return the number of FJTaskRunner threads in this group | 
|  void | stats()Prints various snapshot statistics to System.out. | 
| Methods inherited from class java.lang.Object | 
|---|
| clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait | 
| Field Detail | 
|---|
protected final FJTaskRunner[] threads
protected final LinkedQueue entryQueue
protected int activeCount
protected int nstarted
static final boolean COLLECT_STATS
long initTime
int entries
static final int DEFAULT_SCAN_PRIORITY
static final long SCANS_PER_SLEEP
This is not treated as a user-tunable parameter because good values do not appear to vary much across JVMs or applications. Its main role is to help avoid some useless spinning and contention during task startup.
static final long MAX_SLEEP_TIME
| Constructor Detail | 
|---|
public FJTaskRunnerGroup(int groupSize)
The threads in a FJTaskRunnerGroup are created with their isDaemon status set, so do not normally need to be shut down manually upon program termination.
| Method Detail | 
|---|
public void execute(java.lang.Runnable r)
             throws java.lang.InterruptedException
FJTask.Wrap.
execute in interface Executorjava.lang.InterruptedException - if current Thread is
 currently interruptedpublic void executeTask(FJTask t)
public void invoke(java.lang.Runnable r)
            throws java.lang.InterruptedException
java.lang.InterruptedException - if current Thread is
 interrupted before completion of the task.public void interruptAll()
public void setScanPriorities(int pri)
public void setRunPriorities(int pri)
public int size()
public int getActiveCount()
public void stats()
Cautions: Some statistics are updated and gathered without synchronization, so may not be accurate. However, reported counts may be considered as lower bounds of actual values. Some values may be zero if classes are compiled with COLLECT_STATS set to false. (FJTaskRunner and FJTaskRunnerGroup classes can be independently compiled with different values of COLLECT_STATS.) Also, the counts are maintained as ints so could overflow in exceptionally long-lived applications.
These statistics can be useful when tuning algorithms or diagnosing problems. For example:
protected FJTaskRunner[] getArray()
protected FJTask pollEntryQueue()
protected boolean getActive(FJTaskRunner t)
protected void setActive(FJTaskRunner t)
protected void setInactive(FJTaskRunner t)
protected void checkActive(FJTaskRunner t,
                           long scans)
The main underlying reason for these mechanics is that threads do not signal each other when they add elements to their queues. (This would add to task overhead, reduce locality. and increase contention.) So we must rely on a tamed form of polling. However, tasks inserted into the entry queue do result in signals, so tasks can wait on these if all of them are otherwise idle.
protected void signalNewTask()
protected void initializeThreads()
| 
 | |||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | ||||||||