001 /*
002 Copyright (c) 1996-2012, Damon Hart-Davis
003 All rights reserved.
004
005 Redistribution and use in source and binary forms, with or without
006 modification, are permitted provided that the following conditions are
007 met:
008
009 * Redistributions of source code must retain the above copyright
010 notice, this list of conditions and the following disclaimer.
011
012 * Redistributions in binary form must reproduce the above copyright
013 notice, this list of conditions and the following disclaimer in the
014 documentation and/or other materials provided with the
015 distribution.
016
017 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028 */
029 package org.hd.d.pg2k.svrCore;
030
031 import java.lang.management.OperatingSystemMXBean;
032 import java.util.concurrent.ArrayBlockingQueue;
033 import java.util.concurrent.ExecutorService;
034 import java.util.concurrent.Executors;
035 import java.util.concurrent.Future;
036 import java.util.concurrent.SynchronousQueue;
037 import java.util.concurrent.ThreadFactory;
038 import java.util.concurrent.ThreadPoolExecutor;
039 import java.util.concurrent.TimeUnit;
040 import java.util.concurrent.atomic.AtomicInteger;
041
042 import org.hd.d.pg2k.svrCore.props.LocalProps;
043
044
045 /**Utilities to assist with threading/concurrency.
046 */
047 public final class ThreadUtils
048 {
049 /**Prevent creation of instances. */
050 private ThreadUtils() { }
051
052
053 /**A factory for creating daemon pool threads.
054 * Adapted (purloined) from Doug Lea / Sun JVM code.
055 */
056 public static final class DaemonThreadFactory implements ThreadFactory
057 {
058 private final ThreadGroup group;
059 private final AtomicInteger threadNumber = new AtomicInteger(1);
060 private final String namePrefix;
061 private final boolean lowPriority;
062
063 public DaemonThreadFactory(final String poolName,
064 final boolean lowPriority)
065 {
066 final SecurityManager s = System.getSecurityManager();
067 group = (s != null)? s.getThreadGroup() :
068 Thread.currentThread().getThreadGroup();
069 namePrefix = "pool-" + poolName + "-thread-";
070 this.lowPriority = lowPriority;
071 }
072
073 public Thread newThread(final Runnable r)
074 {
075 final Thread t = new Thread(group, r,
076 namePrefix + threadNumber.getAndIncrement(),
077 0);
078 t.setDaemon(true);
079 if(lowPriority)
080 { t.setPriority(Thread.MIN_PRIORITY); }
081 else if(t.getPriority() != Thread.NORM_PRIORITY)
082 { t.setPriority(Thread.NORM_PRIORITY); }
083 return(t);
084 }
085 }
086
087
088 /**If this system property is set and parsable, then the system behaves as if the specified number of CPUs is available at start-up.
089 * This can be used to stress-test the system,
090 * or to avoid grabbing all the CPUs in a shared system,
091 * or when the JVM/system notion of CPU is not very suitable for us, eg with early HyperThreading.
092 * <p>
093 * Any value set for the property should be strictly positive
094 * when parsed as if by Integer.getInteger().
095 */
096 public static final String PROCESSOR_COUNT_OVERRIDE_SYSPNAME = "org.hd.d.pg2k.CPUs";
097
098 /**If non-null (ie the system property is set and parsable and we are allowed access), then the system behaves as if the specified number of CPUs is available at start-up. */
099 private static final Integer FORCED_CPU_COUNT;
100 static
101 {
102 Integer count = null;
103 try { count = Integer.getInteger(PROCESSOR_COUNT_OVERRIDE_SYSPNAME, null); }
104 catch(final Exception e) { /* Silently absorb error, eg due to security exception. */ }
105 FORCED_CPU_COUNT = count;
106 }
107
108 /**Estimated number of CPUs available; strictly positive.
109 * Usually the JVM/system count of available processors when this class is initialised,
110 * but can be overridden manually.
111 */
112 public static final int AVAILABLE_PROCESSORS = (FORCED_CPU_COUNT == null) ?
113 Runtime.getRuntime().availableProcessors() :
114 Math.max(1, FORCED_CPU_COUNT.intValue());
115
116 /**Approximate maximum concurrent low-priority pool threads; strictly positive.
117 * We may refuse to queue some (discardable) threads
118 * when at least this many of our threads are running.
119 */
120 private static final int MAX_LO_PRI_THREADS = Math.max(1, (AVAILABLE_PROCESSORS/2));
121
122 /**Maximum number of threads that may run in nonCPUThreadPool(); strictly positive.
123 * We limit the amount of threading by:
124 * <ul>
125 * <li>The likely limit on back-end connectivity (eg HTTP-limited).
126 * <li>The likely strain on other resources, such as disc and memory.
127 * </ul>
128 * <p>
129 * Observation suggests that up to 8 threads should be deployed
130 * to extract maximum throughput from a single magnetic disc spindle
131 * given I/O delays from seeking and from I/O bandwidth delays,
132 * so we should always deploy something like that
133 * (though solid-state storage is essentially seek-free with less latency),
134 * rising slowly with the number of CPUs because
135 * I/O capacity probably grows somewhat with CPU count.
136 * <p>
137 * Note also that we may place network-based work
138 * and other I/O blocked items in this pool.
139 * <p>
140 * This starts at 4 for uniprocessors.
141 */
142 private static final int MAX_THREADS_NCTP = 4 + (AVAILABLE_PROCESSORS/4);
143
144 /**Shared non-reconfigurable thread pool for compute-bound activities.
145 * Suitable for almost-entirely CPU-bound threads
146 * (though we allow for a little parallel slackness),
147 * and so the pool size is bounded to a value roughly proportional to
148 * the number of CPUs available to this JVM (at creation of this pool).
149 * <p>
150 * Work cannot be queued for this pool
151 * (ie tasks are always executed immediately),
152 * and excess work (with no free pool threads available)
153 * will be run directly in the caller's thread.
154 * <p>
155 * This puts an upper bound on Thread resources (eg memory for stack)
156 * consumed by threads in this pool.
157 * <p>
158 * The threads in the pool are daemon threads,
159 * so should not prevent the JVM from exiting.
160 */
161 private static final ThreadPoolExecutor _computeIntensiveThreadPool = new ThreadPoolExecutor(1, 1 + ((5*AVAILABLE_PROCESSORS)/4),
162 600L, TimeUnit.SECONDS, // Keep worker threads alive for 10 minutes...
163 new SynchronousQueue<Runnable>(),
164 new DaemonThreadFactory("ThreadUtils.computeIntensiveThreadPool", false),
165 new ThreadPoolExecutor.CallerRunsPolicy());
166 /**Allow these threads to timeout and release all resources. */
167 static { _computeIntensiveThreadPool.allowCoreThreadTimeOut(true); }
168
169 /**Returns approximate space (spare threads) currently available in the computeIntensivePool; non-negative. */
170 public static int computeIntensiveThreadPoolSpace()
171 { return(_computeIntensiveThreadPool.getMaximumPoolSize() - _computeIntensiveThreadPool.getActiveCount()); }
172
173 /**Shared non-reconfigurable thread pool for compute-bound activities.
174 * Suitable for almost-entirely CPU-bound threads
175 * (though we allow for a little parallel slackness),
176 * and so the pool size is bounded to a value roughly proportional to
177 * the number of CPUs available to this JVM (at creation of this pool).
178 * <p>
179 * By preference, this should be used for tasks that may block user interaction,
180 * or that really need to use every available CPU for some critical work;
181 * anything else should use a lower-priority pool if possible.
182 * <p>
183 * Work cannot be queued for this pool
184 * (ie tasks are always executed immediately),
185 * and excess work (with no free pool threads available)
186 * will be run directly in the caller's thread.
187 * <p>
188 * This puts an upper bound on Thread resources (eg memory for stack)
189 * consumed by threads in this pool.
190 * <p>
191 * The threads in the pool are daemon threads,
192 * so should not prevent the JVM from exiting.
193 */
194 public static final ExecutorService computeIntensiveThreadPool =
195 Executors.unconfigurableExecutorService(_computeIntensiveThreadPool);
196
197 /**Shared thread pool for I/O-bound activities. */
198 private static final ThreadPoolExecutor _nonCPUThreadPool = new ThreadPoolExecutor(1, MAX_THREADS_NCTP,
199 300L, TimeUnit.SECONDS, // Keep worker threads alive for 5 minutes...
200 new SynchronousQueue<Runnable>(),
201 new ThreadUtils.DaemonThreadFactory("ThreadUtils.nonCPUThreadPool", false),
202 new ThreadPoolExecutor.CallerRunsPolicy());
203 /**Allow these threads to timeout and release all resources. */
204 static { _nonCPUThreadPool.allowCoreThreadTimeOut(true); }
205
206 /**Shared non-reconfigurable thread pool for I/O-bound activities.
207 * Suitable for relatively short-lived and/or I/O-bound threads,
208 * thus we have a fixed thread/resource limit.
209 * <p>
210 * Work cannot be queued for this pool
211 * (ie tasks are always executed immediately),
212 * and excess work (with no free pool threads available)
213 * will be run directly in the caller's thread.
214 * <p>
215 * We always try to keep one or two worker threads alive for fast response.
216 * <p>
217 * The threads in the pool are daemon threads,
218 * so should not prevent the JVM from exiting.
219 */
220 public static final ExecutorService nonCPUThreadPool =
221 Executors.unconfigurableExecutorService(_nonCPUThreadPool);
222
223 /**Returns approximate space (spare threads) currently available in the nonCPUThreadPool; non-negative. */
224 public static int nonCPUThreadPoolSpace()
225 { return(_nonCPUThreadPool.getMaximumPoolSize() - _nonCPUThreadPool.getActiveCount()); }
226
227 /**Shared non-reconfigurable thread pool for discardable low-priority I/O-bound activities.
228 * Suitable for non-critical relatively I/O-bound threads,
229 * thus we have a fixed thread/resource limit.
230 * <p>
231 * Work cannot be queued for this pool
232 * (ie tasks are always executed immediately or silently discarded).
233 * <p>
234 * The threads in the pool are daemon threads,
235 * so should not prevent the JVM from exiting.
236 */
237 private static final ThreadPoolExecutor _nonCPUThreadPoolDiscardable =
238 (new ThreadPoolExecutor(1, Math.max(2, MAX_THREADS_NCTP/2),
239 300L, TimeUnit.SECONDS, // Keep worker threads alive for 5 minutes...
240 new SynchronousQueue<Runnable>(),
241 new ThreadUtils.DaemonThreadFactory("ThreadUtils.nonCPUThreadPoolDiscardable", true),
242 new ThreadPoolExecutor.DiscardPolicy()) {
243 /**Only allow new task here if CPU not overloaded or pool empty, else silently discard. */
244 @Override public void execute(final Runnable command)
245 { if(nonCPUThreadPoolDiscardableSpace() > 0) { super.execute(command); } }
246 });
247 /**Allow these threads to timeout and release all resources. */
248 static { _nonCPUThreadPoolDiscardable.allowCoreThreadTimeOut(true); }
249 /**Shared non-reconfigurable thread pool for discardable I/O-bound activities.
250 * Suitable for non-critical relatively I/O-bound threads,
251 * thus we have a fixed thread/resource limit.
252 * <p>
253 * Work cannot be queued for this pool
254 * (ie tasks are always executed immediately or silently discarded).
255 * <p>
256 * The threads in the pool are daemon threads,
257 * so should not prevent the JVM from exiting.
258 */
259 public static final ExecutorService nonCPUThreadPoolDiscardable =
260 Executors.unconfigurableExecutorService(_nonCPUThreadPoolDiscardable);
261
262 /**Returns approximate space (spare threads) currently available in the nonCPUThreadPoolDiscardable; non-negative.
263 * Pool size is approximately capped at 1 if CPU is heavily loaded.
264 */
265 public static int nonCPUThreadPoolDiscardableSpace()
266 { return(Math.max(0, (isCPUHeavilyLoaded() ? 1 : _nonCPUThreadPoolDiscardable.getMaximumPoolSize()) - _nonCPUThreadPoolDiscardable.getActiveCount())); }
267
268
269 /**Mutable implementation of thread pool for low-priority compute-bound activities. */
270 private static final ThreadPoolExecutor _lowPriorityThreadPool =
271 new ThreadPoolExecutor(1, MAX_LO_PRI_THREADS,
272 120L, TimeUnit.SECONDS, // Keep worker threads alive for 2 minutes...
273 new SynchronousQueue<Runnable>(),
274 new DaemonThreadFactory("ThreadUtils.lowPriorityThreadPool : ExecutorService", true),
275 new ThreadPoolExecutor.CallerRunsPolicy());
276 /**Allow these threads to timeout and release all resources. */
277 static { _lowPriorityThreadPool.allowCoreThreadTimeOut(true); }
278
279 /**Returns approximate space (spare threads) currently available in the lowPriorityThreadPool; non-negative. */
280 public static int lowPriorityThreadPoolSpace()
281 { return(_lowPriorityThreadPool.getMaximumPoolSize() - _lowPriorityThreadPool.getActiveCount()); }
282
283 /**Shared non-reconfigurable thread pool for low-priority compute-bound activities.
284 * Suitable for almost-entirely CPU-bound threads
285 * and so the pool size is bounded to a value roughly proportional to
286 * (less than) the number of CPUs available to this JVM (at creation of this pool).
287 * <p>
288 * Work cannot be queued for this pool
289 * (ie tasks are always executed immediately),
290 * and excess work (with no free pool threads available)
291 * will be run directly in the caller's thread.
292 * <p>
293 * These threads run with minimum priority.
294 * <p>
295 * Tasks submitted to this pool <em>should not</em>
296 * consume heavy resources (such as memory) other than CPU
297 * so that we can run many of them at once,
298 * though we try not to use more than half the CPUs at once
299 * when there are multiple CPUs available.
300 * <p>
301 * This puts an upper bound on Thread resources (eg memory for stack)
302 * consumed by threads in this pool.
303 * <p>
304 * The threads in the pool are daemon threads,
305 * so should not prevent the JVM from exiting.
306 */
307 public static final ExecutorService lowPriorityThreadPool =
308 Executors.unconfigurableExecutorService(_lowPriorityThreadPool);
309
310
311 /**Mutable implementation of thread pool for discardable low-priority compute-bound activities. */
312 private static final ThreadPoolExecutor _lowPriorityThreadPoolDiscardable =
313 (new ThreadPoolExecutor(1, Math.max(1, MAX_LO_PRI_THREADS),
314 60L, TimeUnit.SECONDS, // Keep worker threads alive for 1 minute...
315 ((MAX_LO_PRI_THREADS > 1) ? new ArrayBlockingQueue<Runnable>(MAX_LO_PRI_THREADS-1) : new SynchronousQueue<Runnable>()), // Possibly allow some queueing to try to minimise discards.
316 new DaemonThreadFactory("ThreadUtils.lowPriorityThreadPoolDiscardable : ExecutorService", true),
317 new ThreadPoolExecutor.DiscardPolicy()) {
318 /**Only allow new task here if not already too many CPU-bond threads running, else silently discard. */
319 @Override public void execute(final Runnable command)
320 { if(_dontDiscardLowPriCPUBoundTask()) { super.execute(command); } }
321 });
322 /**Allow these threads to timeout and release all resources. */
323 static { _lowPriorityThreadPoolDiscardable.allowCoreThreadTimeOut(true); }
324
325 /**If true then a low-priority CPU-bound task need not be discarded if the thread pool has room and the system is not too busy.
326 * Conversely, when this is false, discard such tasks even when the pool could take them.
327 * <p>
328 * Note that the test of system load may be too expensive.
329 */
330 private static boolean _dontDiscardLowPriCPUBoundTask()
331 { return(_cpuIntensiveThreadsRunningNotOverLimit(MAX_LO_PRI_THREADS - 1) && !ThreadUtils.isCPUHeavilyLoaded()); }
332
333 /**Returns approximate space (spare threads) currently available in the lowPriorityThreadPoolDiscardable; non-negative. */
334 public static int lowPriorityThreadPoolDiscardableSpace()
335 { return(_lowPriorityThreadPoolDiscardable.getMaximumPoolSize() - _lowPriorityThreadPoolDiscardable.getActiveCount()); }
336
337 /**Returns true if it may be possible to have a low-priority discardable task run immediately.
338 * This also indicates in general that the thread pools are not very busy
339 * and a true return can be regarded as an <em>indication</em> to that effect.
340 * <p>
341 * This returning true is no guarantee that a low-priority discardable task
342 * that is immediately submitted will be run, however,
343 * since other threads may attempt to (and manage to) start a task
344 * that would make this false.
345 */
346 public static boolean couldRunLowPriorityDiscardableTask()
347 { return((lowPriorityThreadPoolDiscardableSpace() > 0) && _dontDiscardLowPriCPUBoundTask()); }
348
349 /**Shared non-reconfigurable thread pool for discardable low-priority compute-bound activities.
350 * Most suitable for almost-entirely CPU-bound threads,
351 * and so the pool size is bounded to a value roughly proportional to
352 * (but less than) the number of CPUs available to this JVM (at creation of this pool).
353 * <p>
354 * This prefers to queue tasks and execute them on a small number of CPUs,
355 * only potentially increasing the pool size if the queue fills.
356 * (This will only queue tasks on a machine with a significant number of CPUs,
357 * where it could run more than one of these tasks at once, eg not on a uniprocessor.)
358 * <p>
359 * When this pool and its queue are full,
360 * or other CPU-bound pools appear to be using all available CPUs,
361 * then <em>this silently discards new tasks submitted</em>.
362 * <p>
363 * These threads run with minimum priority.
364 * <p>
365 * Tasks submitted to this pool <em>should not</em> generally
366 * consume heavy resources (such as memory) other than CPU
367 * so that we can safely run many of them at once.
368 * This pool tries not to use more than half the CPUs at once
369 * when there are multiple CPUs available.
370 * <p>
371 * A bounded (small) amount of work can be queued for this pool
372 * (ie tasks are usually executed immediately or should not wait long),
373 * and excess work (with no free pool threads or queue space available)
374 * will be <em>silently discarded</em>.
375 * <p>
376 * This puts an upper bound on Thread resources (eg memory for stack)
377 * consumed by threads in this pool.
378 * <p>
379 * The threads in the pool are daemon threads,
380 * so should not prevent the JVM from exiting.
381 */
382 public static final ExecutorService lowPriorityThreadPoolDiscardable =
383 Executors.unconfigurableExecutorService(_lowPriorityThreadPoolDiscardable);
384
385 /**Returns true if the count of (non-I/O-bound) threads running in our pools is no higher than the specified limit.
386 * This is only likely to be an approximation
387 * since there is no synchronisation, etc,
388 * and statistical parameters are being combined here.
389 *
390 * @param limit expected to be non-negative
391 * (but may be negative resulting in always returning false)
392 */
393 private static boolean _cpuIntensiveThreadsRunningNotOverLimit(final int limit)
394 {
395 int count = 0;
396 // Order these to minimise run-time.
397 if(limit < (count += _computeIntensiveThreadPool.getActiveCount())) { return(false); }
398 if(limit < (count += _lowPriorityThreadPool.getActiveCount())) { return(false); }
399 if(limit < (count += _lowPriorityThreadPoolDiscardable.getActiveCount())) { return(false); }
400 return(true);
401 }
402
403 /**Dump some diagnostics during startup. */
404 static
405 {
406 /* if(IsDebug.isDebug) */
407 {
408 System.out.println("INFO: ThreadUtils: init: available processors="+AVAILABLE_PROCESSORS+
409 ", MAX_LO_PRI_THREADS="+MAX_LO_PRI_THREADS+
410 ", MAX_THREADS_NCTP="+MAX_THREADS_NCTP);
411 }
412 }
413
414 /**Return a Future that already has its result computed. */
415 public static <T> Future<T> makeCompletedFuture(final T r)
416 {
417 return new Future<T>(){
418 public boolean cancel(final boolean mayInterruptIfRunning)
419 { return(false); }
420 public T get() // throws InterruptedException, ExecutionException
421 { return(r); }
422 public T get(final long timeout, final TimeUnit unit) // throws InterruptedException, ExecutionException, TimeoutException
423 { return(r); }
424 public boolean isCancelled()
425 { return(false); }
426 public boolean isDone()
427 { return(true); }
428 };
429 }
430
431
432 /**If false, then it seems to be unsafe to try to check system load.
433 * Avoid uptime check on some early 1.6.0 pre-releases that crash...
434 */
435 private static final boolean CHECK_UPTIME = !System.getProperty("java.version").startsWith("1.6.0-d");
436
437 /**Get load fraction in queued jobs per CPU over last minute (like UNIX load average, but normalised); -1 if unavailable otherwise non-negative.
438 * A value of 0 indicates an idle system in CPU terms,
439 * a value of 1 indicates fully-utilised CPUs,
440 * and a value greater than one indicates more work available than CPUs to run it.
441 * <p>
442 * Like the UNIX load average, but divided by the number of CPUs to normalise it.
443 */
444 public static float loadFraction()
445 {
446 if(!CHECK_UPTIME) { return(-1f); }
447 final OperatingSystemMXBean operatingSystemMXBean = java.lang.management.ManagementFactory.getOperatingSystemMXBean();
448 final int cpus = operatingSystemMXBean.getAvailableProcessors();
449 final float loadAverage = (float) operatingSystemMXBean.getSystemLoadAverage();
450 if(loadAverage < 0) { return(-1f); }
451 if(cpus == 1) { return(loadAverage); }
452 return(loadAverage / cpus);
453 }
454
455 /**Private flag for cpuHeavilyLoaded() to note time when we last sampled.
456 * Given that the underlying value is on the scale of a minute,
457 * we need only sample on a similar timescale,
458 * though to detect and respond quickly to overload a few seconds is probably best.
459 * <p>
460 * Initially zero.
461 * <p>
462 * Marked volatile for thread-safe lock-free access.
463 */
464 private static volatile long _lastHeavilyLoadSampleTime;
465
466 /**Private cache for cpuHeavilyLoaded(): True if system was heavily loaded at last sample, False if lightly loaded.
467 * Initially null.
468 * <p>
469 * Marked volatile for thread-safe lock-free access.
470 */
471 private static volatile Boolean _lastHeavilyLoadSample;
472
473 /**Returns TRUE if CPU known to be heavily loaded over the last minute or so, FALSE if lightly loaded, else null if load 'normal'.
474 * May be cached for efficiency, eg to avoid expensive system calls and floating-point arithmetic.
475 * <p>
476 * When running well, the system should over around the normal / light-load boundary.
477 * <p>
478 * May retain/cache 'heavily loaded' value longer (ie asymmetrically).
479 */
480 public static Boolean cpuHeavyLoad()
481 {
482 final long now = System.currentTimeMillis();
483 final Boolean wasHeavilyLoaded = _lastHeavilyLoadSample;
484 if(_lastHeavilyLoadSampleTime + ((Boolean.TRUE == wasHeavilyLoaded) ? 8192 : 2048) > now) { return(wasHeavilyLoaded); } // From cache.
485 _lastHeavilyLoadSampleTime = now; // Postpone next sampling (to try to avoid race with this one).
486 final Boolean nowHeavilyLoaded; // New sample.
487 final float loadFraction = loadFraction();
488 if(loadFraction >= LocalProps.getHeavyLoadMin()) { nowHeavilyLoaded = Boolean.TRUE; }
489 else if(loadFraction < LocalProps.getLightLoadMax()) { nowHeavilyLoaded = Boolean.FALSE; }
490 else { nowHeavilyLoaded = null; }
491 _lastHeavilyLoadSample = nowHeavilyLoaded; // Cache result...
492 return(nowHeavilyLoaded);
493 }
494
495 /**Returns true if CPU known to be heavily loaded over the last minute or so, else false.
496 * May be cached for efficiency, eg to avoid expensive system calls and floating-point arithmetic.
497 */
498 public static boolean isCPUHeavilyLoaded()
499 { return(Boolean.TRUE == cpuHeavyLoad()); }
500
501 /**Returns true if CPU known to be lightly loaded over the last minute or so, else false.
502 * May be cached for efficiency, eg to avoid expensive system calls and floating-point arithmetic.
503 */
504 public static boolean isCPULightlyLoaded()
505 { return(Boolean.FALSE == cpuHeavyLoad()); }
506 }