![JAR search and dependency download from the Maven repository](/logo.png)
com.amlinv.javasched.impl.StandardNonBlockingSchedulerEngine Maven / Gradle / Ivy
/*
* Copyright 2015 AML Innovation & Consulting LLC
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.amlinv.javasched.impl;
import com.amlinv.javasched.NonBlockingSchedulerEngine;
import com.amlinv.javasched.Step;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.LinkedBlockingQueue;
/**
* Created by art on 12/8/14.
*/
public class StandardNonBlockingSchedulerEngine implements NonBlockingSchedulerEngine {
private static final Logger DEFAULT_LOGGER = LoggerFactory
.getLogger(StandardNonBlockingSchedulerEngine.class);
private Logger log = DEFAULT_LOGGER;
private int processorCount;
private Object processorSync = new Object();
private ProcessorThread[] processorThreads;
private boolean started;
private boolean stopped;
private LinkedBlockingQueue stepQueue = new LinkedBlockingQueue<>();
////////////////////////
//
// PUBLIC METHODS
//
////////////////////////
/**
* Create the non-blocking scheduler engine using the given number of processors.
*
* @param processorCount number of processor threads to use for execution of tasks.
*/
public StandardNonBlockingSchedulerEngine(int processorCount) {
this.processorCount = processorCount;
}
/**
* Create the non-blocking scheduler engine with auto-detection of the number of system
* processors using Runtime.availableProcessors(). Creates one less processing thread than
* the number of detected system processors so one processor is always available for scheduler
* and other activities, unless the system processor count is 1, in which case the processor
* count falls-back to 1.
*
* Process count is aut-detected using Runtime.availableProcessors().
*/
public StandardNonBlockingSchedulerEngine() {
int numSysProcessor = Runtime.getRuntime().availableProcessors();
this.processorCount = Math.max(numSysProcessor - 1, 1);
}
public int getProcessorCount() {
return this.processorCount;
}
public void setProcessorCount(int newNumProcessor) {
this.processorCount = newNumProcessor;
}
public Logger getLog() {
return log;
}
public void setLog(Logger log) {
this.log = log;
}
@Override
public void start() {
synchronized (this.processorSync) {
if (this.started) {
throw new IllegalStateException("already started");
}
if (this.processorCount < 1) {
throw new IllegalStateException("processor count must be positive");
}
this.started = true;
}
//
// Allocate all the processor threads and start them.
//
this.processorThreads = new ProcessorThread[this.processorCount];
int iter = 0;
while (iter < this.processorCount) {
this.processorThreads[iter] = new ProcessorThread(iter);
this.processorThreads[iter].start();
iter++;
}
}
public void initiateShutdown() {
synchronized (this.processorSync) {
if (!this.started) {
throw new IllegalStateException("not yet started");
}
if (this.stopped) {
throw new IllegalStateException("already stopped");
}
this.stopped = true;
}
for (ProcessorThread processorThread : processorThreads) {
processorThread.interrupt();
}
}
@Override
public void submit(Step nonBlockingStep) {
if (!this.started) {
throw new IllegalStateException("not yet started");
}
if (this.stopped) {
throw new IllegalStateException("scheduler already stopped");
}
if ( nonBlockingStep == null ) {
throw new NullPointerException();
}
boolean added = this.stepQueue.offer(nonBlockingStep);
if (!added) {
throw new RuntimeException("internal error: unbounded queue of steps rejected offered step");
}
}
////////////////////////
//
// INTERNAL METHODS
//
////////////////////////
protected void injectQueueForTest(LinkedBlockingQueue injectQueue) {
this.stepQueue = injectQueue;
}
/**
* Grab the next step, waiting if necessary.
*
* @param threadNum number of the processor thread waiting for the step.
* @return the next step to execute.
*/
protected Step waitForStep(int threadNum) throws InterruptedException {
Step nextStep;
nextStep = this.stepQueue.take();
return nextStep;
}
protected class ProcessorThread extends Thread {
private StandardNonBlockingSchedulerEngine parent = StandardNonBlockingSchedulerEngine.this;
private int threadNumber;
private boolean running = true;
public ProcessorThread(int threadNumber) {
super("standard-non-blocking-scheduler-processor-thread#" + threadNumber);
this.threadNumber = threadNumber;
}
@Override
public void run() {
while (this.running && (!parent.stopped)) {
try {
Step execStep = parent.waitForStep(this.threadNumber);
try {
execStep.execute();
} catch (Exception exc) {
parent.log.warn("failed step execution", exc);
}
} catch (InterruptedException intExc) {
parent.log.info("stopping processor thread #{} on interrupt", this.threadNumber);
this.running = false;
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy