001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.system.thread;
020
021import icy.system.IcyExceptionHandler;
022import icy.system.SystemUtil;
023
024import java.awt.EventQueue;
025import java.lang.reflect.InvocationTargetException;
026import java.util.concurrent.Callable;
027import java.util.concurrent.ExecutionException;
028import java.util.concurrent.ExecutorService;
029import java.util.concurrent.Future;
030import java.util.concurrent.FutureTask;
031import java.util.concurrent.TimeUnit;
032
033import javax.swing.SwingUtilities;
034
035/**
036 * Thread utilities class.
037 * 
038 * @author Stephane
039 */
040public class ThreadUtil
041{
042    /**
043     * This class is used to catch exception in the EDT.
044     */
045    public static class CaughtRunnable implements Runnable
046    {
047        private final Runnable runnable;
048
049        public CaughtRunnable(Runnable runnable)
050        {
051            super();
052
053            this.runnable = runnable;
054        }
055
056        @Override
057        public void run()
058        {
059            try
060            {
061                runnable.run();
062            }
063            catch (Throwable t)
064            {
065                IcyExceptionHandler.handleException(t, true);
066            }
067        }
068    }
069
070    /**
071     * The minimum priority that a thread can have.
072     */
073    public final static int MIN_PRIORITY = Thread.MIN_PRIORITY;
074
075    /**
076     * The default priority that is assigned to a thread.
077     */
078    public final static int NORM_PRIORITY = Thread.NORM_PRIORITY;
079
080    /**
081     * The maximum priority that a thread can have.
082     */
083    public final static int MAX_PRIORITY = Thread.MAX_PRIORITY;
084
085    // low priority background processor
086    private static final Processor bgProcessor;
087    // single Runnable / Callable instance processor
088    private static final InstanceProcessor instanceProcessors[];
089    // low priority single Runnable / Callable instance processor
090    private static final InstanceProcessor bgInstanceProcessors[];
091
092    static
093    {
094        if (SystemUtil.is32bits())
095        {
096            int wantedThread = SystemUtil.getNumberOfCPUs();
097            wantedThread = Math.max(wantedThread, 2);
098
099            // 32 bits JVM, limit the number of thread
100            bgProcessor = new Processor(Math.min(wantedThread, 8));
101            instanceProcessors = new InstanceProcessor[Math.min(wantedThread, 4)];
102            bgInstanceProcessors = new InstanceProcessor[Math.min(wantedThread, 4)];
103        }
104        else
105        {
106            int wantedThread = SystemUtil.getNumberOfCPUs();
107            wantedThread = Math.max(wantedThread, 4);
108
109            // 64 bits JVM, can have higher limit
110            bgProcessor = new Processor(Math.min(wantedThread, 16));
111            instanceProcessors = new InstanceProcessor[Math.min(wantedThread, 8)];
112            bgInstanceProcessors = new InstanceProcessor[Math.min(wantedThread, 8)];
113        }
114
115        bgProcessor.setPriority(MIN_PRIORITY);
116        bgProcessor.setThreadName("Background processor");
117        bgProcessor.setKeepAliveTime(3, TimeUnit.SECONDS);
118
119        for (int i = 0; i < instanceProcessors.length; i++)
120        {
121            // keep these thread active
122            instanceProcessors[i] = new InstanceProcessor(NORM_PRIORITY);
123            instanceProcessors[i].setThreadName("Background instance processor");
124            instanceProcessors[i].setKeepAliveTime(3, TimeUnit.SECONDS);
125            bgInstanceProcessors[i] = new InstanceProcessor(MIN_PRIORITY);
126            bgInstanceProcessors[i].setThreadName("Background instance processor (low priority)");
127            bgInstanceProcessors[i].setKeepAliveTime(3, TimeUnit.SECONDS);
128        }
129    }
130
131    /**
132     * Shutdown all background runner.
133     */
134    public static void shutdown()
135    {
136        bgProcessor.shutdown();
137        for (int i = 0; i < instanceProcessors.length; i++)
138        {
139            instanceProcessors[i].shutdown();
140            bgInstanceProcessors[i].shutdown();
141        }
142    }
143
144    /**
145     * Return true if all background runner are shutdown and terminated.
146     */
147    public static boolean isShutdownAndTerminated()
148    {
149        for (int i = 0; i < instanceProcessors.length; i++)
150        {
151            if (!instanceProcessors[i].isTerminated())
152                return false;
153            if (!bgInstanceProcessors[i].isTerminated())
154                return false;
155        }
156        return bgProcessor.isTerminated();
157    }
158
159    /**
160     * @return true if the current thread is an AWT event dispatching thread.
161     */
162    public static boolean isEventDispatchThread()
163    {
164        return EventQueue.isDispatchThread();
165    }
166
167    /**
168     * Invoke the specified <code>Runnable</code> on the AWT event dispatching thread.<br>
169     * Any exception is automatically caught by Icy exception handler.
170     * 
171     * @param wait
172     *        If set to true, the method wait until completion, in this case you have to take
173     *        attention to not cause any dead lock.
174     * @see #invokeLater(Runnable)
175     * @see #invokeNow(Runnable)
176     */
177    public static void invoke(Runnable runnable, boolean wait)
178    {
179        if (wait)
180            invokeNow(runnable);
181        else
182            invokeLater(runnable);
183    }
184
185    /**
186     * @deprecated Use {@link #invokeNow(Runnable)} instead
187     */
188    @Deprecated
189    public static void invokeAndWait(Runnable runnable)
190    {
191        invokeNow(runnable);
192    }
193
194    /**
195     * Invoke the specified <code>Runnable</code> on the AWT event dispatching thread now and wait
196     * until completion.<br>
197     * Any exception is automatically caught by Icy exception handler, if you want to catch them use
198     * {@link #invokeNow(Callable)} instead.<br>
199     * Use this method carefully as it may lead to dead lock.
200     */
201    public static void invokeNow(Runnable runnable)
202    {
203        if (isEventDispatchThread())
204        {
205            try
206            {
207                runnable.run();
208            }
209            catch (Throwable t)
210            {
211                // the runnable thrown an exception
212                IcyExceptionHandler.handleException(t, true);
213            }
214        }
215        else
216        {
217            try
218            {
219                EventQueue.invokeAndWait(runnable);
220            }
221            catch (InvocationTargetException e)
222            {
223                // the runnable thrown an exception
224                IcyExceptionHandler.handleException(e.getTargetException(), true);
225            }
226            catch (InterruptedException e)
227            {
228                // interrupt exception
229                System.err.println("ThreadUtil.invokeNow(...) error :");
230                IcyExceptionHandler.showErrorMessage(e, true);
231            }
232        }
233    }
234
235    /**
236     * Invoke the specified <code>Runnable</code> on the AWT event dispatching thread.<br>
237     * If we already are on the EDT the <code>Runnable</code> is executed immediately else it will
238     * be executed later.
239     * 
240     * @see #invokeLater(Runnable, boolean)
241     */
242    public static void invokeLater(Runnable runnable)
243    {
244        invokeLater(runnable, false);
245    }
246
247    /**
248     * Invoke the specified <code>Runnable</code> on the AWT event dispatching thread.<br>
249     * Depending the <code>forceLater</code> parameter the <code>Runnable</code> can be executed
250     * immediately if we are on the EDT.
251     * 
252     * @param forceLater
253     *        If <code>true</code> the <code>Runnable</code> is forced to execute later even if we
254     *        are on the Swing EDT.
255     */
256    public static void invokeLater(Runnable runnable, boolean forceLater)
257    {
258        final Runnable r = new CaughtRunnable(runnable);
259
260        if ((!forceLater) && isEventDispatchThread())
261            r.run();
262        else
263            EventQueue.invokeLater(r);
264    }
265
266    /**
267     * Invoke the specified <code>Callable</code> on the AWT event dispatching thread now and return
268     * the result.<br>
269     * The returned result can be <code>null</code> when a {@link Throwable} exception happen.<br>
270     * Use this method carefully as it may lead to dead lock.
271     * 
272     * @throws InterruptedException
273     *         if the current thread was interrupted while waiting
274     * @throws Exception
275     *         if the computation threw an exception
276     */
277    public static <T> T invokeNow(Callable<T> callable) throws Exception
278    {
279        if (SwingUtilities.isEventDispatchThread())
280            return callable.call();
281
282        final FutureTask<T> task = new FutureTask<T>(callable);
283
284        try
285        {
286            EventQueue.invokeAndWait(task);
287        }
288        catch (InvocationTargetException e)
289        {
290            if (e.getTargetException() instanceof Exception)
291                throw (Exception) e.getTargetException();
292
293            throw new Exception(e.getTargetException());
294        }
295
296        try
297        {
298            return task.get();
299        }
300        catch (ExecutionException e)
301        {
302            if (e.getCause() instanceof Exception)
303                throw (Exception) e.getCause();
304
305            throw new Exception(e.getCause());
306        }
307    }
308
309    /**
310     * Invoke the specified {@link Callable} on the AWT event dispatching thread.<br>
311     * Depending the <code>forceLater</code> parameter the <code>Callable</code> can be executed
312     * immediately if we are on the EDT.
313     * 
314     * @param forceLater
315     *        If <code>true</code> the <code>Callable</code> is forced to execute later even if we
316     *        are on the EDT.
317     */
318    public static <T> Future<T> invokeLater(Callable<T> callable, boolean forceLater)
319    {
320        final FutureTask<T> task = new FutureTask<T>(callable);
321        invokeLater(task, forceLater);
322        return task;
323    }
324
325    /**
326     * Retrieve the instance processor (normal priority) to use for specified runnable.
327     */
328    private static InstanceProcessor getInstanceProcessor(Runnable runnable)
329    {
330        // get processor index from the hash code
331        return instanceProcessors[runnable.hashCode() % instanceProcessors.length];
332    }
333
334    /**
335     * Retrieve the instance processor (normal priority) to use for specified callable.
336     */
337    private static InstanceProcessor getInstanceProcessor(Callable<?> callable)
338    {
339        // get processor index from the hash code
340        return instanceProcessors[callable.hashCode() % instanceProcessors.length];
341    }
342
343    /**
344     * Retrieve the instance processor (low priority) to use for specified runnable.
345     */
346    private static InstanceProcessor getBgInstanceProcessor(Runnable runnable)
347    {
348        // get processor index from the hash code
349        return bgInstanceProcessors[runnable.hashCode() % bgInstanceProcessors.length];
350    }
351
352    /**
353     * Retrieve the instance processor (low priority) to use for specified callable.
354     */
355    private static InstanceProcessor getBgInstanceProcessor(Callable<?> callable)
356    {
357        // get processor index from the hash code
358        return bgInstanceProcessors[callable.hashCode() % bgInstanceProcessors.length];
359    }
360
361    /**
362     * @deprecated Use {@link #bgRun(Runnable)} instead and {@link #invokeNow(Runnable)} separately.
363     * @see #bgRun(Runnable)
364     */
365    @Deprecated
366    public static boolean bgRun(Runnable runnable, boolean onEDT)
367    {
368        return (bgProcessor.submit(runnable, onEDT) != null);
369    }
370
371    /**
372     * @deprecated Use {@link #bgRun(Runnable)} instead and check for acceptance.
373     */
374    @Deprecated
375    public static void bgRunWait(Runnable runnable)
376    {
377        while (!bgRun(runnable))
378            ThreadUtil.sleep(1);
379    }
380
381    /**
382     * Adds background processing (low priority) of specified Runnable.<br>
383     * Returns <code>false</code> if background process queue is full.<br>
384     * Don't use this method for long process (more than 1 second) as the number of thread is
385     * limited and others processes may be executed too late.
386     */
387    public static boolean bgRun(Runnable runnable)
388    {
389        return (bgProcessor.submit(true, runnable) != null);
390    }
391
392    /**
393     * @deprecated Use {@link #bgRun(Callable)} and {@link #invokeNow(Callable)} separately instead.
394     * @see #bgRun(Callable)
395     */
396    @Deprecated
397    public static <T> Future<T> bgRun(Callable<T> callable, boolean onEDT)
398    {
399        return bgProcessor.submit(callable, onEDT);
400    }
401
402    /**
403     * Adds background processing (low priority) of specified Callable task.<br>
404     * Returns a Future representing the pending result of the task or <code>null</code> if
405     * background process queue is full.<br>
406     * Don't use this method for long process (more than 1 second) as the number of thread is
407     * limited and others processes may be executed too late.
408     */
409    public static <T> Future<T> bgRun(Callable<T> callable)
410    {
411        return bgProcessor.submit(callable);
412    }
413
414    /**
415     * @deprecated Use {@link #runSingle(Runnable)} instead and {@link #invokeNow(Runnable)} separately.
416     * @see #bgRunSingle(Runnable)
417     */
418    @Deprecated
419    public static boolean bgRunSingle(Runnable runnable, boolean onEDT)
420    {
421        final InstanceProcessor processor = getInstanceProcessor(runnable);
422        return (processor.submit(runnable, onEDT) != null);
423    }
424
425    /**
426     * @deprecated Use {@link #runSingle(Callable)} and {@link #invokeNow(Callable)} separately
427     *             instead.
428     * @see #bgRunSingle(Callable)
429     */
430    @Deprecated
431    public static <T> Future<T> bgRunSingle(Callable<T> callable, boolean onEDT)
432    {
433        final InstanceProcessor processor = getInstanceProcessor(callable);
434        return processor.submit(callable, onEDT);
435    }
436
437    /**
438     * Adds single processing (low priority) of specified Runnable.<br>
439     * If this <code>Runnable</code> instance is already pending in single processes queue then
440     * nothing is done.<br>
441     * Returns <code>false</code> if single processes queue is full.<br>
442     * Don't use this method for long process (more than 1 second) as the number of thread is
443     * limited and others processes may be executed too late.
444     */
445    public static boolean bgRunSingle(Runnable runnable)
446    {
447        final InstanceProcessor processor = getBgInstanceProcessor(runnable);
448        return (processor.submit(true, runnable) != null);
449    }
450
451    /**
452     * Adds single processing (low priority) of specified Callable task.<br>
453     * If this <code>Callable</code> instance is already pending in single processes queue then
454     * nothing is done.<br>
455     * Returns a Future representing the pending result of the task or <code>null</code> if
456     * single processes queue is full.<br>
457     * Don't use this method for long process (more than 1 second) as the number of thread is
458     * limited and others processes may be executed too late.
459     */
460    public static <T> Future<T> bgRunSingle(Callable<T> callable)
461    {
462        final InstanceProcessor processor = getBgInstanceProcessor(callable);
463        return processor.submit(callable);
464    }
465
466    /**
467     * Add single processing (normal priority) of specified Runnable.<br>
468     * If this <code>Runnable</code> instance is already pending in single processes queue then
469     * nothing is done.<br>
470     * Return <code>false</code> if single processes queue is full.<br>
471     * Don't use this method for long process (more than 1 second) as the number of thread is
472     * limited and others processes may be executed too late.
473     */
474    public static boolean runSingle(Runnable runnable)
475    {
476        final InstanceProcessor processor = getInstanceProcessor(runnable);
477        return (processor.submit(true, runnable) != null);
478    }
479
480    /**
481     * Add single processing (normal priority) of specified Callable task.<br>
482     * If this <code>Callable</code> instance is already pending in single processes queue then
483     * nothing is done.<br>
484     * Return a Future representing the pending result of the task or <code>null</code> if
485     * single processes queue is full.<br>
486     * Don't use this method for long process (more than 1 second) as the number of thread is
487     * limited and others processes may be executed too late.
488     */
489    public static <T> Future<T> runSingle(Callable<T> callable)
490    {
491        final InstanceProcessor processor = getInstanceProcessor(callable);
492        return processor.submit(callable);
493    }
494
495    /**
496     * Return true if the specified runnable is waiting to be processed in background processing.
497     */
498    public static boolean hasWaitingBgTask(Runnable runnable)
499    {
500        return bgProcessor.getWaitingTasksCount(runnable) > 0;
501    }
502
503    /**
504     * Return true if the specified callable is waiting to be processed in background processing.
505     */
506    public static boolean hasWaitingBgTask(Callable<?> callable)
507    {
508        return bgProcessor.getWaitingTasksCount(callable) > 0;
509    }
510
511    /**
512     * Return true if the specified runnable is waiting to be processed<br>
513     * in single scheme background processing (low priority).
514     */
515    public static boolean hasWaitingBgSingleTask(Runnable runnable)
516    {
517        final InstanceProcessor processor = getBgInstanceProcessor(runnable);
518        return processor.hasWaitingTasks(runnable);
519    }
520
521    /**
522     * Return true if the specified callable is waiting to be processed<br>
523     * in single scheme background processing (low priority).
524     */
525    public static boolean hasWaitingBgSingleTask(Callable<?> callable)
526    {
527        final InstanceProcessor processor = getBgInstanceProcessor(callable);
528        return processor.hasWaitingTasks(callable);
529    }
530
531    /**
532     * Return true if the specified runnable is waiting to be processed<br>
533     * in single scheme background processing (normal priority).
534     */
535    public static boolean hasWaitingSingleTask(Runnable runnable)
536    {
537        final InstanceProcessor processor = getInstanceProcessor(runnable);
538        return processor.hasWaitingTasks(runnable);
539    }
540
541    /**
542     * Return true if the specified callable is waiting to be processed<br>
543     * in single scheme background processing (normal priority).
544     */
545    public static boolean hasWaitingSingleTask(Callable<?> callable)
546    {
547        final InstanceProcessor processor = getInstanceProcessor(callable);
548        return processor.hasWaitingTasks(callable);
549    }
550
551    /**
552     * Return the number of active background tasks.
553     */
554    public static int getActiveBgTaskCount()
555    {
556        return bgProcessor.getActiveCount();
557    }
558
559    /**
560     * Create a thread pool with the given name.<br>
561     * The number of processing thread is automatically calculated given the number of core of the
562     * system.
563     * 
564     * @see Processor#Processor(int, int, int)
565     */
566    public static ExecutorService createThreadPool(String name)
567    {
568        final Processor result = new Processor(SystemUtil.getNumberOfCPUs());
569
570        result.setThreadName(name);
571
572        return result;
573    }
574
575    /**
576     * Same as {@link Thread#sleep(long)} except Exception is caught and ignored.
577     */
578    public static void sleep(long milli)
579    {
580        try
581        {
582            Thread.sleep(milli);
583        }
584        catch (InterruptedException e)
585        {
586            // have to interrupt the thread
587            Thread.currentThread().interrupt();
588        }
589    }
590
591    /**
592     * Same as {@link Thread#sleep(long)} except Exception is caught and ignored.
593     */
594    public static void sleep(int milli)
595    {
596        try
597        {
598            Thread.sleep(milli);
599        }
600        catch (InterruptedException e)
601        {
602            // have to interrupt the thread
603            Thread.currentThread().interrupt();
604        }
605    }
606}