All Downloads are FREE. Search and download functionalities are using the official Maven repository.

blueprint.sdk.core.concurrent.WorkerGroup Maven / Gradle / Ivy

The newest version!
/*
 License:

 blueprint-sdk is licensed under the terms of Eclipse Public License(EPL) v1.0
 (http://www.eclipse.org/legal/epl-v10.html)


 Distribution:

 Maven Central - https://search.maven.org/artifact/io.github.lempel/blueprint-sdk
 MVN Repository - https://mvnrepository.com/artifact/io.github.lempel/blueprint-sdk
 */

package blueprint.sdk.core.concurrent;

import blueprint.sdk.util.jvm.shutdown.TerminatableThread;
import blueprint.sdk.util.jvm.shutdown.Terminator;
import blueprint.sdk.util.queue.Queue;
import blueprint.sdk.util.reflect.Crowbar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * A Group of Workers
* Maintains JobQueue and Workers
*
* If you want to use automatic thread spanning feature, call start() method.
* * @param Job Type * @param Queue Type * @author [email protected] * @since 2008. 11. 25. */ public class WorkerGroup> extends TerminatableThread { /** * check interval (msec) */ protected static final int INTERVAL = 1000; /** * worker thread increase ratio */ static final float THREAD_INC_RATIO = 0.2f; private static final Logger L = LoggerFactory.getLogger(WorkerGroup.class); protected final Class> workerClass; protected final Q jobQueue; protected final List> workers; /** * monitor for dead workers */ protected final Object deathMonitor = new Object(); final int initialWorkers; /** * Constructor * * @param jobQueue job queue * @param workerClass Worker class * @param workerCount Initial number of workers */ public WorkerGroup(final Q jobQueue, final Class> workerClass, final int workerCount) { // register to shutdown hook (Terminator) Terminator.getInstance().register(this); this.jobQueue = jobQueue; this.workers = new ArrayList<>(workerCount); this.workerClass = workerClass; initialWorkers = workerCount; setName(this.getClass().getName()); setDaemon(true); L.info("worker group created - worker: {}, count: {}", workerClass, workerCount); } /** * create and add a new Worker * * @throws NoSuchMethodException * @throws InstantiationException * @throws IllegalAccessException * @throws InvocationTargetException */ protected void newWorker() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { Worker aWorker; Constructor[] constructors = workerClass.getConstructors(); for (Constructor constructor : constructors) { Parameter[] params = constructor.getParameters(); if (params == null || params.length != 2) { continue; } if (Crowbar.isInstance(params[0].getType(), Queue.class) && Crowbar.isInstance(params[1].getType(), Object.class)) { // FIXME how can I resolve this warning? aWorker = (Worker) constructor.newInstance(jobQueue, deathMonitor); workers.add(aWorker); aWorker.start(); break; } } } /** * Add more workers * * @param count number of workers */ void addWorkers(final int count) { int failure = 0; synchronized (workers) { for (int i = 0; i < count; i++) { try { newWorker(); } catch (Exception e) { L.error("worker creation failed - " + e); failure++; } } } int diff = (count - failure); if (diff > 0) { L.info("worker added - class: {}, count: {} (+{})", workerClass, workers.size(), diff); } } /** * Remove some workers.
*
* Removed workers are subjected to terminate. Not immediate.
*
* You can't remove all workers. At least 1 worker will survive.
* * @param count number of workers */ void removeWorkers(int count) { int removed = 0; synchronized (workers) { for (int i = 0; i < count && workers.size() > 1; i++) { workers.remove(0).terminate(); removed++; } } if (removed > 0) { L.info("worker removed - class: {}, count: {} (-{})", workerClass, workers.size(), removed); } } @Override public void terminate() { running = false; synchronized (deathMonitor) { deathMonitor.notifyAll(); } if (workers != null) { synchronized (workers) { for (Worker worker : workers) { worker.terminate(); } } } } public void addJob(final J job) { jobQueue.push(job); } @Override public void run() { try { // instantiate & start workers for (int i = 0; i < initialWorkers; i++) { newWorker(); } running = true; } catch (Exception e) { L.error("Can't create workers. Terminating " + getClass().getSimpleName(), e); } while (running) { maintainWorkers(); synchronized (deathMonitor) { try { deathMonitor.wait(); } catch (InterruptedException ignored) { } } } terminated = true; } /** * Check all workers and replace terminated with new ones. */ void maintainWorkers() { synchronized (workers) { int workerCount = workers.size(); Iterator> iter = workers.iterator(); while (iter.hasNext()) { Worker worker = iter.next(); if (worker.isTerminated()) { iter.remove(); } } int delta = workerCount - workers.size(); for (int i = 0; i < delta; i++) { try { newWorker(); } catch (Exception e) { L.warn("Can't create new worker - " + workerClass.getName(), e); } } } } public String getActivity() { return "queued=" + jobQueue.size() + ", workers=" + workers.size() + ", processing=" + getActiveWorkerCount(); } int getActiveWorkerCount() { int result = 0; for (Worker worker : workers) { if (worker.isActive()) { result++; } } return result; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy