Skip to content

McCapy/AsyncTask

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Dynamic AsyncTask Manager

An API that allows you to execute, parallelize, and async code dynamically, and simply.

Note

This is a shadable project.

Warning

This project is very early in development. Beware that the API WILL change, although functionality will still be extremely performant and well > verse.

Note

Any changes applied to the "main" branch will be production ready, there will never be any unstable commited to the main branch unless it's considered experimental.

Installation

This is how to add this project as either a dependency, or just using it outright.

You will start by first navigating to this link:

https://jitpack.io/#McCapy/AsyncTask

This will direct you to the jitpack page, this will instruct you on how to apply this in your pom, or pom equivalent, allowing you to use the API itself. I HIGHLY Recommend using the latest commit. If you must, avoid EXPERIMENTAL code.

Deinitialization

This is a very important step if you're using this for any project with processes that effect persistent data. This includes things like minecraft plugins, anything with a persistent database, etc.

Deinitializing will prevent all forms of data-leaks for processes like this, as well as modifying data post disable.

import org.DynamicThread.TaskManager;

/// This is how you disable the TaskManager, and by extension; all running threads.
/// However, for other forms of processes; like minecraft plugins, you would
/// execute the code seen below the one that can be seen here.
void main() {
    TaskManager.disable();
}
import org.DynamicThread.TaskManager;

// This is the-obvious but proper-way to deinitialize your plugin.
// Remember, if you forget to do this, you **WILL** have a memory leak.
public final MyPlugin extends JavaPlugin {

    @Override
    public void onDisable() {
        TaskManager.disable();
    }
}

Features & Methods

While there are sparse features, there is a large sum of methods you can use to suit your needs.

Features

  • The ability to run code parallel.
  • The ability to run code async.
  • The ability to run code async, later joining it into the parent thread.
  • The ability to collect values from threads.
  • More can be seen through methods, which will explain in more detail.

Note

This is Extremely important to know, There are TWO types of AsyncTask's

  • Runnables
  • Returnables

Runnables have a AsyncTask<Void> type Returnables have a AsyncTask<?> where ? is NOT Void

Runnables only execute tasks, While returnables execute a task & return a result, this result from the task can be passed onto hooked tasks. See "Hooking Tasks" for more information on this.

Methods

For this method there are actually quite a few overloads, they can be seen below.

AsyncTask.of(Runnable... runnables);
AsyncTask.of(Supplier<?> supplier, Runnable... runnables);
AsyncTask.of(Supplier<?> supplier);

For each of these respectively they all have different functionalities.

  1. The first, this simply executes all supplied tasks in parallel, and then calls all hooked tasks (see Hooking Tasks)
  2. The second, this will also quite simply, execute the supplied runnables, and then execute the supplier last. This can be used for coordinated exterior tasks.
  3. The third and final, executes the supplier and passes the result into future hooked tasks. (see Hooking Tasks)

Hooking Tasks

This specific tab is going to have A LOT of methods, and even more overloads. Each method has slightly different function then its parent method.

AsyncTask.after(Runnable... runnables);
AsyncTask.after(Consumer<?>... consumers);
AsyncTask.after(Function<?,?> function, Consumer<?>... consumers);
AsyncTask.after(Supplier<?> supplier);
AsyncTask.after(Supplier<?> supplier, Runnable... runnables);
AsyncTask.after(Supplier<?> supplier, Consumer<?>... consumers);
AsyncTask.after(Function<?,?> function,Runnable... runnables);
AsyncTask.after(Function<?,?> function);

Naturally these will all have to be explained,

  1. The first, will run all the submitted tasks in parallel after the previous task is completed
  2. The second, executes the submitted tasks in parallel, they accept the previous tasks output.
  3. The third, executes the submitted consumers first, once all are completed, the function will execute. passing the value on.
  4. The fourth, returns a value and executes the process, this can be used to transform the type of chain (See paragraph below)
  5. The fifth, executes all submitted runnables in parallel firstly, nextly executes the supplier.
  6. The sixth, executes all submitted consumers with the previous tasks output, and then executes the supplier.
  7. The seventh, executes the submitted runnables, and then the inputted function.
  8. The eighth and final one, simply takes the output from the previous task, and passes the result to the next task.

Behavior & Hooking Tasks

While examples and explanations will be provided further down, we will provide clarifications here.

  1. Firstly, Runnables and Returnables can be converted between each other fluidly through **.after()**
  2. Secondly, .after() should not be used as a substitution for .onComplete() or other events tied to threads. See more about events after this section.
void main() {
  AsyncTask<Integer> runnableToReturnable = 
      AsyncTask.of(() -> System.out.println("I Executed!")) // only a runnable
          .after(() -> 15) // it's now a returnable of type "Integer"
          .start(); // start thread to execute, will print "I Executed" and nothing else.
}

Events

Events naturally are quite an important thing to have, for some platforms they drive the entire institution. However in our case, events are hooked into the sole usage of this, you can even use this API as the structure for event-oriented-programming (EOP) Such as waiting for a thread to run, post run use .onComplete() to make it call a method which can do its respective task as well. This is what makes the API so flexible, and so powerful as well.

However, events do have their little caveat. using .onComplete() applies the event to the CURRENT task, see below

void main() {
  AsyncTask<Integer> task = AsyncTask.of(() -> 15)
      .onComplete((item) -> System.out.println("First thread task completed with result, " + item))
      .after((item) -> item * 2)
      .onComplete((item) -> System.out.println("Entire thread completed with result, " + item));
}

This may look slightly confusing however we can break this apart quite simply; we have 2 tasks in total, the first being return 15 and the second being, return item * 2 item in our case would be 15, because it was passed in through the first task, however, .onComplete() will fire twice, once for the first task, and again for the last task, printing their respective things, item in this entire scenario will be the result from the previous task. The methods behind the events will be detailed more in the following section.

AsyncTask.onStart(Runnable runnable);
AsyncTask.onComplete(Consumer<?> consumer);
AsyncTask.onTimeout(Runnable runnable);
AsyncTask.onError(Consumer<Throwable> consumer);

Again, all of these will be explained.

  1. The first, executes whenever a task starts.
  2. The second, executes whenever the task completes, it takes output for the Consumers<?> parameter.
  3. The third, Executes whenever a task times out.
  4. The fourth, executes whenever an error occurs, its parameter is the error that was thrown.
  5. The only thing you really need to know is, the event attaches to the task directly behind it.

Thread Behavior

While the functionality may seem intimidating it's still very similar to threads, that's because it IS threads! You still have the .start() .join() .join(long timeOut) methods naturally, as well as .cancel() among others. These will all be described and clarified naturally.

AsyncTask.isCompleted();
AsyncTask.isCancelled();
AsyncTask.isTimedOut();
AsyncTask.timeout(long time);
AsyncTask.cancel();
AsyncTask.join();
AsyncTask.join(long time);
AsyncTask.collect();
AsyncTask.collet(long time);
AsyncTask.cancel(long time);
  1. The first, returns true if the task is completed.
  2. The second, returns true if the task is cancelled.
  3. The third, returns true if the task has timed out.
  4. The fourth, sets the time, in milliseconds, it takes for the task to timeout.
  5. The fifth, cancels the task.
  6. The sixth, joins the task back into the main thread, returning the result of the task overall.
  7. The seventh, joins the task back into the main thread after a given amount of time in milliseconds.
  8. The eighth, is effectively the same to .join() however, it is for syntactical clarity
  9. The ninth nextly, is effectively the same to .join(long time) however, it is for syntactical clarity.
  10. The tenth and final one, is a delayed .cancel()

Examples

void main() throws InterruptedException {
  AsyncTask<String> task = AsyncTask.of(
      () -> 10,
      () -> System.out.println("Task 1"), // shows that the tasks are parallelized
      () -> System.out.println("Task 2"),
      () -> System.out.println("Task 3"),
      () -> System.out.println("Task 4"),
      () -> System.out.println("Task 5")
  ) // creates a returnable of type integer

  .onStart(() -> {
      System.out.println("Started main task");
  }) // shows when the task starts

  .after((item) -> {
      return item + 3;
  }) // returns 13 (doesn't change return type)

  .after((item) -> {
      System.out.println("Resulted in " + item);
      System.out.println("Changed type to a runnable");
  }) // converts to runnable

  .after(() -> {
      System.out.println("Changed type back to returnable, its type is String");
      return "capybara";
  }) // converts to returnable of type string

  .onComplete((item) -> {
      System.out.println("Entire task completed with result " + item);
  }) // calls after the entire task is completed
  .start();

  System.out.println("Sleep Started");
  Thread.sleep(1500); // proves it's actually asynced
  System.out.println("Sleep Ended");
  System.out.println("Collecting results of the task back into main thread with result: "  + task.collect());
}

Console Output

The console output can be seen below, this naturally proves all I've depicted in the code.

Started main task
Sleep Started
Task 1
Task 5
Task 3
Task 2
Task 4
Resulted in 13
Changed type to a runnable
Changed type back to returnable, its type is String
Entire task completed with result capybara
Sleep Ended
Collecting results of the task back into main thread with result: capybara

About

A very simple API that allows for the execution and paralellization of code, this can be used for either background tasks or main thread tasks., the possibilities are truly endless!

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages