/* * JGrass - Free Open Source Java GIS http://www.jgrass.org * (C) Falko Bräutigam, polymap.de * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) any * later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more * details. * * You should have received a copy of the GNU Library General Public License * along with this library; if not, write to the Free Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jgrasstools.gears.libs.modules.multiprocessing; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; /** * An {@link ExecutionPlanner} provides the logic to distribute the processing of * many small {@link MultiProcessingTask}s over a limited number of execution * threads. This is crucial for efficient parallel execution. * * @author Falko Bräutigam */ public abstract class ExecutionPlanner { static { ThreadFactory threadFactory = new ThreadFactory() { volatile int threadNumber = 0; @Override public Thread newThread( Runnable r ) { Thread t = new Thread( r, "process-worker-" + threadNumber++ ); t.setDaemon( false ); //t.setPriority( DEFAULT_THREAD_PRIORITY ); return t; } }; int procNum = Runtime.getRuntime().availableProcessors(); ThreadPoolExecutor threadPool = new ThreadPoolExecutor( procNum, procNum, 60L, TimeUnit.SECONDS, // with BlockingExecutorService on top we can have unbound queue new LinkedTransferQueue(), // new LinkedBlockingDeque( procNum ), // new SynchronousQueue(), // new ArrayBlockingQueue( procNum ) ); threadFactory ); defaultExecutor = new BlockingExecutorService( threadPool, procNum ); } /** * The default {@link ExecutorService} to be used by all planners. * <p/> * Set this to change the default. The {@link ExecutorService} must not have an * unbound queue or an unlimited number of threads. In other words, the executor * has to refuse submits when system resources are running out. */ public static final BlockingExecutorService defaultExecutor; /** * Set this to change the default planner for all modules. */ public static Supplier<ExecutionPlanner> defaultPlannerFactory = () -> new FixedChunkSizePlanner(); //new InThreadExecutionPlanner(); /** * Creates a new general purpose, default {@link ExecutionPlanner}. This is * returned by {@link MultiProcessing#createDefaultPlanner()} by default. */ public static ExecutionPlanner createDefaultPlanner() { return defaultPlannerFactory.get(); } // instance ******************************************* protected int numberOfTasks = -1; /** * Hints this planner about the total number of task until next {@link #join()}. */ public ExecutionPlanner setNumberOfTasks( int num ) { this.numberOfTasks = num; return this; } /** * Submits the given task for execution. * <p/> * * @param task */ public abstract void submit( MultiProcessingTask task ); /** * Blocks the calling thread until all sumitted task have completed execution. * * @throws Exception If a previously submitted task has thrown an exception then * it is re-thrown by the join() method. */ public abstract void join() throws Exception; }