All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.exactpro.sf.services.TaskExecutor Maven / Gradle / Ivy
/******************************************************************************
* Copyright 2009-2018 Exactpro (Exactpro Systems Limited)
*
* Licensed 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.exactpro.sf.services;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TaskExecutor implements ITaskExecutor
{
private static final Logger logger = LoggerFactory.getLogger(TaskExecutor.class);
private static final int POSSIBLE_DELAY = 10;
private static final String EXECUTOR_PREFIX = TaskExecutor.class.getSimpleName() + '-';
private static final AtomicLong taskCounter = new AtomicLong();
private final ExecutorService threadPool;
private final ScheduledExecutorService scheduledThreadPool;
public TaskExecutor() {
this(0, 350, Runtime.getRuntime().availableProcessors() * 2);
}
public TaskExecutor(int minThreads, int maxThreads, int scheduledThreads) {
threadPool = new ThreadPoolExecutor(minThreads, maxThreads, 30L, TimeUnit.SECONDS, new SynchronousQueue());
scheduledThreadPool = Executors.newScheduledThreadPool(scheduledThreads);
}
@Override
public synchronized Future addTask(Callable task)
{
return threadPool.submit(new TaskCallableWrapper(task));
}
@Override
public synchronized Future> addTask(Runnable task)
{
return threadPool.submit(new TaskRunnableWrapper(task));
}
@Override
public synchronized Future> schedule(Runnable task, long delay, TimeUnit timeUnit) {
return scheduledThreadPool.schedule(new TaskRunnableWrapper(task, timeUnit.toMillis(delay)), delay, timeUnit);
}
@Override
public synchronized Future> schedule(Callable task, long delay, TimeUnit timeUnit) {
return scheduledThreadPool.schedule(new TaskCallableWrapper(task, timeUnit.toMillis(delay)), delay, timeUnit);
}
@Override
public synchronized Future> addRepeatedTask(Runnable task, long initialDelay, long delay, TimeUnit timeUnit) {
return scheduledThreadPool.scheduleWithFixedDelay(new TaskRepeatableWrapper(task, initialDelay, delay), initialDelay, delay, timeUnit);
}
@Override
public void dispose()
{
if(!threadPool.isShutdown() || !scheduledThreadPool.isShutdown()) {
logger.info("TaskExecutor disposing started...");
try {
if(!threadPool.isShutdown()) {
threadPool.shutdownNow();
if(!threadPool.awaitTermination(5000, TimeUnit.MILLISECONDS)) {
logger.warn("Some Threads from cachedThreadPool remained alive");
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
try {
if(!scheduledThreadPool.isShutdown()) {
scheduledThreadPool.shutdownNow();
if(!scheduledThreadPool.awaitTermination(5000, TimeUnit.MILLISECONDS)) {
logger.warn("Some Threads from scheduledThreadPool remained alive");
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
if(!threadPool.isTerminated() || !scheduledThreadPool.isTerminated()) {
logger.error("Not all tasks have been completed in timeout");
}
}
}
@Override
public ExecutorService getThreadPool() {
return threadPool;
}
private void setThreadName(Thread thread, String name) {
try {
thread.setName(name);
} catch (Exception e) {
logger.warn("Failed to set the thread name.", e);
}
}
private String createThreadName(String taskName) {
return new StringBuilder(EXECUTOR_PREFIX)
.append(taskName).append('-')
.append(taskCounter.incrementAndGet()).toString();
}
/**
* Logging exception that were thrown in the task and
* checking delay time between creating and running task.
*/
private class TaskRunnableWrapper implements Runnable {
protected final Runnable wrappedTask;
protected final String threadName;
protected long createTime;
public TaskRunnableWrapper(Runnable wrappedTask, long delay) {
this.wrappedTask = wrappedTask;
this.threadName = createThreadName(wrappedTask.toString());
this.createTime = System.currentTimeMillis() + delay;
}
public TaskRunnableWrapper(Runnable wrappedTask) {
this(wrappedTask, 0);
}
@Override
public void run() {
long timeInQueue = System.currentTimeMillis() - createTime;
String oldName = null;
Thread currentThread = null;
if(threadName != null) {
currentThread = Thread.currentThread();
oldName = currentThread.getName();
setThreadName(currentThread, threadName);
}
try {
executeTask(timeInQueue);
} finally {
if(currentThread != null && threadName != null) {
setThreadName(currentThread, oldName);
}
}
}
private void executeTask(long timeInQueue) {
if(timeInQueue > POSSIBLE_DELAY) {
logger.warn("Task [{}] delay exceed on {}", wrappedTask, timeInQueue);
}
try {
wrappedTask.run();
} catch (RuntimeException e) {
logger.error(e.getMessage(), e);
throw e;
}
}
}
/**
* Logging exception that were thrown in the task and
* checking delay time between creating and running task.
*/
private class TaskCallableWrapper implements Callable {
protected final Callable wrappedTask;
protected final String threadName;
protected long createTime;
public TaskCallableWrapper(Callable wrappedTask, long delay) {
this.wrappedTask = wrappedTask;
this.threadName = createThreadName(wrappedTask.toString());
this.createTime = System.currentTimeMillis() + delay;
}
public TaskCallableWrapper(Callable wrappedTask) {
this(wrappedTask, 0);
}
@Override
public T call() throws Exception {
long timeInQueue = System.currentTimeMillis() - createTime;
String oldName = null;
Thread currentThread = null;
if(threadName != null) {
currentThread = Thread.currentThread();
oldName = currentThread.getName();
setThreadName(currentThread, threadName);
}
try {
return executeTask(timeInQueue);
} finally {
if(currentThread != null && threadName != null) {
setThreadName(currentThread, oldName);
}
}
}
private T executeTask(long timeInQueue) throws Exception {
if(timeInQueue > POSSIBLE_DELAY) {
logger.warn("Task [{}] delay exceed on {}", wrappedTask, timeInQueue);
}
return wrappedTask.call();
}
}
/**
* Logging exception that were thrown in the task and
* checking delay time between creating and running task.
*/
private class TaskRepeatableWrapper extends TaskRunnableWrapper {
private final long delay;
public TaskRepeatableWrapper(Runnable wrappedTask, long initialDelay, long delay) {
super(wrappedTask, initialDelay);
this.delay = delay;
}
@Override
public void run() {
super.run();
this.createTime = System.currentTimeMillis() + delay;
}
}
}