fabric-synctask #1
@ -0,0 +1,4 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
public interface AsyncTaskI extends TaskI, AutoCloseable {
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package fr.altarik.toolbox.task;
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
public interface TaskI extends AutoCloseable {
|
public interface TaskI {
|
||||||
|
|
||||||
public void addTask(AltarikRunnable function) throws InterruptedException;
|
public void addTask(AltarikRunnable function) throws InterruptedException;
|
||||||
|
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.syncTasks.SchedulerTaskData;
|
||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
public class TaskScheduler {
|
||||||
|
private Vector<SchedulerTaskData> asyncTasks;
|
||||||
|
private boolean stop = false;
|
||||||
|
|
||||||
|
|
||||||
|
public synchronized void sendAsyncTask(AltarikRunnable function, long delay, long period) throws InterruptedException {
|
||||||
|
asyncTasks.addElement(new SchedulerTaskData(function, delay, period));
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function executed in asynchronous workers with periodic tasks
|
||||||
|
*/
|
||||||
|
public synchronized void asyncRunnerPeriodicTasks() throws InterruptedException {
|
||||||
|
loop: while(true) {
|
||||||
|
notify();
|
||||||
|
while(asyncTasks.size() == 0) {
|
||||||
|
if(isStop()) {
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
SchedulerTaskData data = asyncTasks.firstElement();
|
||||||
|
asyncTasks.remove(data);
|
||||||
|
if(!data.getFunction().isCancelled()) {
|
||||||
|
long currentDelay = data.getCurrentDelay();
|
||||||
|
if(currentDelay != 0) {
|
||||||
|
data.setCurrentDelay(currentDelay - 1);
|
||||||
|
asyncTasks.addElement(data);
|
||||||
|
} else {
|
||||||
|
data.getFunction().run();
|
||||||
|
data.setCurrentDelay(data.getPeriod());
|
||||||
|
asyncTasks.addElement(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean isStop() {
|
||||||
|
return stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setStop(boolean stop) {
|
||||||
|
this.stop = stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfTasks() {
|
||||||
|
return asyncTasks.size();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package fr.altarik.toolbox.task.asyncTasks;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.*;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntComparators;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI {
|
||||||
|
|
||||||
|
private final ExecutorService worker;
|
||||||
|
private final List<TaskScheduler> schedulers;
|
||||||
|
|
||||||
|
private AsyncPeriodicTasks(int numberOfWorker) {
|
||||||
|
int size = 0;
|
||||||
|
if(numberOfWorker == 1) {
|
||||||
|
worker = Executors.newSingleThreadExecutor();
|
||||||
|
size = 1;
|
||||||
|
} else if (numberOfWorker <= 0) {
|
||||||
|
worker = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||||
|
size = Runtime.getRuntime().availableProcessors();
|
||||||
|
} else {
|
||||||
|
worker = Executors.newFixedThreadPool(numberOfWorker);
|
||||||
|
size = numberOfWorker;
|
||||||
|
}
|
||||||
|
this.schedulers = new ArrayList<>(size);
|
||||||
|
for(int i = 0; i < size; i++) {
|
||||||
|
TaskScheduler scheduler = new TaskScheduler();
|
||||||
|
schedulers.add(scheduler);
|
||||||
|
worker.submit(() -> {
|
||||||
|
try {
|
||||||
|
scheduler.asyncRunnerPeriodicTasks();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this method at startup or before first use of {@link AsyncTasks#addTask(AltarikRunnable)}, cause without it, nothing will work
|
||||||
|
* This method declare worker thread and start it, without call it, by calling addTask(Runnable), it'll add your task to Queue, but tasks will never be consumed.
|
||||||
|
*
|
||||||
|
* @return an instance of AsyncTasks
|
||||||
|
*/
|
||||||
|
public static TaskI initialize(int numberOfWorker) {
|
||||||
|
return new AsyncPeriodicTasks(numberOfWorker);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TaskI initialize() {
|
||||||
|
return initialize(Runtime.getRuntime().availableProcessors());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTask(AltarikRunnable function) throws InterruptedException {
|
||||||
|
this.addTask(function, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException {
|
||||||
|
if(worker.isTerminated() || worker.isShutdown()) {
|
||||||
|
throw new InterruptedException("Worker has been terminated or shutdown, it's impossible to add new task");
|
||||||
|
}
|
||||||
|
schedulers.stream()
|
||||||
|
.min((o1, o2) -> IntComparators.NATURAL_COMPARATOR.compare(o1.getNumberOfTasks(), o2.getNumberOfTasks()))
|
||||||
|
.orElseThrow()
|
||||||
|
.sendAsyncTask(function, delay, period);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
schedulers.forEach(s -> s.setStop(true));
|
||||||
|
worker.shutdown();
|
||||||
|
boolean result = worker.awaitTermination(10, TimeUnit.SECONDS);
|
||||||
|
if(!result) {
|
||||||
|
worker.shutdownNow();
|
||||||
|
throw new AsyncTasks.UnfinishedTasksException("Tasks take too many time to finish, shutdown has been enforce");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,14 +18,14 @@ public class AsyncTasks implements TaskI {
|
|||||||
if(numberOfWorker == 1) {
|
if(numberOfWorker == 1) {
|
||||||
worker = Executors.newSingleThreadExecutor();
|
worker = Executors.newSingleThreadExecutor();
|
||||||
} else if (numberOfWorker <= 0) {
|
} else if (numberOfWorker <= 0) {
|
||||||
worker = Executors.newCachedThreadPool();
|
worker = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||||
} else {
|
} else {
|
||||||
worker = Executors.newFixedThreadPool(numberOfWorker);
|
worker = Executors.newFixedThreadPool(numberOfWorker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this method at startup or before first use of {@link AsyncTasks#addTask(Runnable)}, cause without it, nothing will work
|
* Call this method at startup or before first use of {@link AsyncTasks#addTask(AltarikRunnable)}, cause without it, nothing will work
|
||||||
* This method declare worker thread and start it, without call it, by calling addTask(Runnable), it'll add your task to Queue, but tasks will never be consumed.
|
* This method declare worker thread and start it, without call it, by calling addTask(Runnable), it'll add your task to Queue, but tasks will never be consumed.
|
||||||
*
|
*
|
||||||
* @return an instance of AsyncTasks
|
* @return an instance of AsyncTasks
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package fr.altarik.toolbox.task.syncTasks;
|
package fr.altarik.toolbox.task.syncTasks;
|
||||||
|
|
||||||
import fr.altarik.toolbox.task.AltarikRunnable;
|
import fr.altarik.toolbox.task.AltarikRunnable;
|
||||||
|
import fr.altarik.toolbox.task.PeriodicTaskI;
|
||||||
import fr.altarik.toolbox.task.TaskI;
|
import fr.altarik.toolbox.task.TaskI;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PeriodicSyncTask implements TaskI, Runnable {
|
public class PeriodicSyncTask implements PeriodicTaskI, Runnable {
|
||||||
|
|
||||||
private ServerTickListener listener;
|
private ServerTickListener listener;
|
||||||
private List<AltarikRunnable> tasks;
|
private List<AltarikRunnable> tasks;
|
||||||
@ -26,11 +27,6 @@ public class PeriodicSyncTask implements TaskI, Runnable {
|
|||||||
tasks.add(function);
|
tasks.add(function);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws Exception {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
List<AltarikRunnable> removeList = new ArrayList<>(tasks.size());
|
List<AltarikRunnable> removeList = new ArrayList<>(tasks.size());
|
||||||
@ -44,4 +40,9 @@ public class PeriodicSyncTask implements TaskI, Runnable {
|
|||||||
}
|
}
|
||||||
tasks.removeAll(removeList);
|
tasks.removeAll(removeList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package fr.altarik.toolbox.task.syncTasks;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.AltarikRunnable;
|
||||||
|
|
||||||
|
public class SchedulerTaskData {
|
||||||
|
|
||||||
|
private final long delay;
|
||||||
|
private final long period;
|
||||||
|
private final AltarikRunnable function;
|
||||||
|
|
||||||
|
private long currentDelay;
|
||||||
|
|
||||||
|
public SchedulerTaskData(AltarikRunnable function, long delay, long period) {
|
||||||
|
this.function = function;
|
||||||
|
this.delay = delay;
|
||||||
|
this.period = period;
|
||||||
|
this.currentDelay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AltarikRunnable getFunction() {
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCurrentDelay() {
|
||||||
|
return currentDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentDelay(long currentDelay) {
|
||||||
|
this.currentDelay = currentDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDelay() {
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPeriod() {
|
||||||
|
return period;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user