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.
io.inugami.commons.threads.ThreadsExecutorService Maven / Gradle / Ivy
/* --------------------------------------------------------------------
* Inugami
* --------------------------------------------------------------------
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package io.inugami.commons.threads;
import io.inugami.api.exceptions.Asserts;
import io.inugami.api.exceptions.TechnicalException;
import io.inugami.api.listeners.TaskFinishListener;
import io.inugami.api.listeners.TaskStartListener;
import io.inugami.api.loggers.Loggers;
import io.inugami.api.models.tools.Chrono;
import io.inugami.api.providers.concurrent.LifecycleBootstrap;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
/**
* ThreadsExecutorService
*
* @author patrick_guillerm
* @since 13 janv. 2017
*/
@SuppressWarnings({"java:S1186", "java:S2142", "java:S2139"})
public class ThreadsExecutorService implements LifecycleBootstrap {
// =========================================================================
// ATTRIBUTES
// =========================================================================
private final long timeout;
private final String name;
private final ExecutorService executor;
private final ExecutorService executorCompletable;
// =========================================================================
// CONSTRUCTORS
// =========================================================================
public ThreadsExecutorService(final String name, final int maxThreads) {
this(name, maxThreads, false, null);
}
public ThreadsExecutorService(final String name, final int maxThreads, final boolean deamon) {
this(name, maxThreads, deamon, null);
}
public ThreadsExecutorService(final String name, final int maxThreads, final boolean deamon, final Long timeout) {
this.name = name == null ? "ThreadsExecutor" : name;
final MonitoredThreadFactory threadFactory = new MonitoredThreadFactory(this.name, deamon);
executor = Executors.newFixedThreadPool(maxThreads, threadFactory);
executorCompletable = Executors.newFixedThreadPool(maxThreads, threadFactory);
this.timeout = timeout == null ? 30000L : timeout.longValue();
}
// =========================================================================
// RUN
// =========================================================================
public List> run(final List> tasks) {
return run(tasks, null, null);
}
public List> run(final List> tasks, final BiConsumer> onDone) {
return run(tasks, onDone, null);
}
public List> run(final List> tasks, final BiConsumer> onDone,
final BiConsumer> onError) {
final List> result = new ArrayList<>();
if ((tasks != null) && !tasks.isEmpty()) {
for (int i = 0; i < tasks.size(); i++) {
final CompletableFuture future = buildFuture(tasks.get(i), onDone, onError);
result.add(future);
}
}
return result;
}
// =========================================================================
// RUN AND GRAB
// =========================================================================
public List runAndGrab(final List> tasks) throws TechnicalException {
return runAndGrab(tasks, null, null, timeout);
}
public List runAndGrab(final List> tasks,
final BiConsumer> onDone,
final BiConsumer> onError) throws TechnicalException {
return runAndGrab(tasks, onDone, onError, timeout);
}
public List runAndGrab(final List> tasks, final long timeout) throws TechnicalException {
return runAndGrab(tasks, null, null, timeout);
}
public List runAndGrab(final List> tasks, final BiConsumer> onDone,
final long timeout) throws TechnicalException {
return runAndGrab(tasks, onDone, null, timeout);
}
public List runAndGrab(final List> tasks, final BiConsumer> onDone,
final BiConsumer> onError,
final long timeout) throws TechnicalException {
final List result = new ArrayList<>();
final List> futures = run(tasks, (data, task) -> {
result.add(data);
onDone.accept(data, task);
}, onError);
waitting(futures, timeout);
return result;
}
// =========================================================================
// WAIT
// =========================================================================
public void waitting(final List> futures, final long timeout) throws TechnicalException {
if ((futures != null) && !futures.isEmpty()) {
final Chrono chrono = Chrono.startChrono();
for (final CompletableFuture future : futures) {
chrono.snapshot();
long localTimeout = timeout - chrono.getDuration();
if (localTimeout > 0) {
try {
future.get(localTimeout, TimeUnit.MILLISECONDS);
} catch (final InterruptedException | ExecutionException | TimeoutException e) {
Loggers.PLUGINS.error(e.getMessage());
throw new TechnicalException(e.getMessage(), e);
}
}
}
}
}
// =========================================================================
// BUILDER
// =========================================================================
public CompletableFuture buildFuture(final Callable taskToProcess) {
return buildFuture(taskToProcess, null, null);
}
public CompletableFuture buildFuture(final Callable taskToProcess,
final BiConsumer> onDone) {
return buildFuture(taskToProcess, onDone, null);
}
public CompletableFuture buildFuture(final Callable taskToProcess,
final BiConsumer> onDone,
final BiConsumer> onError) {
// @formatter:off
final BiConsumer> functionOnDone = onDone != null ? onDone : (data, task) -> {
};
final BiConsumer> functionOnError = onError != null ? onError : (error, task) -> {
};
// @formatter:on
final Future future = run(taskToProcess);
final CompletableFuture result = CompletableFuture.supplyAsync(() -> {
T futureResult = null;
try {
futureResult = future.get(timeout, TimeUnit.MILLISECONDS);
} catch (final InterruptedException | ExecutionException | TimeoutException e) {
if ((e instanceof ExecutionException) && (e.getCause() instanceof NoSuchElementException)) {
futureResult = null;
} else {
Loggers.DEBUG.error(e.getMessage(), e);
functionOnError.accept(e, taskToProcess);
future.cancel(true);
}
}
return futureResult;
}, executorCompletable);
result.thenAcceptAsync(data -> functionOnDone.accept(data, taskToProcess));
return result;
}
private Future run(final Callable taskToProcess) {
return executor.submit(taskToProcess);
}
public Future submit(final String name, final Callable task) {
return submit(name, task, null, null);
}
public Future submit(final String name, final Callable task, final TaskFinishListener listener) {
return submit(name, task, listener, null);
}
public Future submit(final String name, final Callable task, final TaskFinishListener finishListner,
final TaskStartListener startListner) {
return executor.submit(new ThreadsExecutorTask(name, task, startListner, finishListner));
}
// =========================================================================
// LifecycleBootstrap
// =========================================================================
@Override
public void start() {
}
@Override
public void shutdown() {
shutdownExecutor(executor);
shutdownExecutor(executorCompletable);
}
private void shutdownExecutor(final ExecutorService localExecutor) {
localExecutor.shutdown();
try {
localExecutor.awaitTermination(500, TimeUnit.MILLISECONDS);
} catch (final InterruptedException e) {
Loggers.DEBUG.debug(e.getMessage(), e);
localExecutor.shutdownNow();
Thread.currentThread().interrupt();
}
}
// =========================================================================
// THREAD
// =========================================================================
private class ThreadsExecutorTask implements Callable {
private final String name;
private final Callable task;
private final TaskStartListener startListner;
private final TaskFinishListener finishListner;
public ThreadsExecutorTask(final String name, final Callable task, final TaskStartListener startListner,
final TaskFinishListener finishListner) {
Asserts.assertNotNull("name mustn't be null!", name);
Asserts.assertNotNull("task mustn't be null!", task);
this.name = name;
this.task = task;
this.startListner = startListner;
this.finishListner = finishListner;
}
@Override
public T call() throws Exception {
final long startTime = System.currentTimeMillis();
if (startListner != null) {
startListner.onStart(startTime, name);
}
final Exception error = null;
T result = null;
try {
result = task.call();
} catch (final Exception e) {
Loggers.DEBUG.error(e.getMessage(), e);
Loggers.XLLOG.error(e.getMessage());
throw e;
} finally {
if (finishListner != null) {
final long endTime = System.currentTimeMillis();
final long delais = startTime - endTime;
finishListner.onFinish(endTime, delais, name, result, error);
}
}
return result;
}
}
public ExecutorService getExecutor() {
return executor;
}
}