Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f953662
commit 61d1b7c
Showing
5 changed files
with
482 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Examples | ||
|
||
## 1. Creating a pooling | ||
|
||
|
||
One of the common usages of **this library** (*[ThreadingTools](https://github.com/Javinator9889/ThreadingTools)*) | ||
is to concurrently run **a predefined number of threads**, but specifying upper limits (for not | ||
running all threads at the same time). | ||
|
||
*ThreadingTools* provides a utility for generating a **pool** of threads that will run | ||
concurrently, `ThreadsPooling`, accessed via `Builder` inner class. | ||
|
||
For creating a new instance, we will use: | ||
|
||
+ `builder()`, for obtaining the builder object. | ||
+ `build()`, for creating the `ThreadsPooling` class. | ||
|
||
All other methods are detailed and specified at the | ||
[official documentation](https://javinator9889.github.io/ThreadingTools/com/github/javinator9889/threading/pools/ThreadsPooling.Builder.html#method.detail) | ||
which explains everything you need to know for creating a new `ThreadsPooling` class. | ||
|
||
---------------- | ||
|
||
```java | ||
import com.github.javinator9889.threading.pools.ThreadsPooling; | ||
|
||
|
||
public class ExampleClass { | ||
private ThreadsPooling mPooling; | ||
|
||
public ExampleClass() { | ||
// Constructor that initializes the ThreadsPooling object | ||
|
||
// In this example, we will use the number of processor | ||
// for defining the concurrent jobs running. | ||
// Also, the maximum jobs running will be twice number | ||
// of processor. | ||
int numberOfProcessors = getNumberOfProcessors(); | ||
int maxProcessRunning = numberOfProcessor * 2; | ||
// We are going to execute at most 20 threads | ||
int queueCapacity = 20; | ||
// We want threads to terminate when they become idle | ||
// after one second | ||
long keepAliveTime = 1L; | ||
|
||
// We are leaving ThreadFactory and | ||
// RejectedExecutionHandler to their defaults | ||
mPooling = ThreadsPooling.builder() | ||
.withConcurrentThreadsRunning(numberOfProcessors) | ||
.withMaximumPoolSize(maxProcessRunning) | ||
.withQueueCapacity(queueCapacity) | ||
.withKeepAliveInSeconds(keepAliveTime) | ||
.build(); | ||
|
||
// Now we have the ThreadsPooling object created | ||
// We could have add the threads we want to execute | ||
// with the methods: "withThread()" and "withThreads" | ||
} | ||
|
||
// Method for getting the generated ThreadsPooling | ||
public ThreadsPooling getPooling() { | ||
return mPooling; | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# Examples | ||
|
||
## 2. Creating a NotifyingThread | ||
|
||
As explained at *README*, there are several ways to know when a **thread** has finished its job: | ||
|
||
+ **Using** a `Future` object, in which you define *what is going to be executed* and then, | ||
wait for its result (if it has one).<br /><br /> | ||
**Advantages**: you will only have the result when the `Future` is done.<br /> | ||
**Disadvantages**: if there is no result, you will not know when the `Future` is done. | ||
|
||
+ **Using** a `Thread` object, and call `join()`, blocking your main thread (or *any other | ||
thread where `join()` was called*) for a non-defined time.<br /><br /> | ||
**Advantages**: you do not need to use any other lib, it is a *built-in*.<br /> | ||
**Disadvantages**: you dedicate a **hole process** to wait for a thread that maybe do not finish. | ||
|
||
With `NotifyingThread`, all those problems disappear, as: | ||
|
||
+ You can **get notified** of the threads *you want to get notified by*. | ||
+ You do not have to **actively wait** for a thread to *finish*. | ||
+ You can use them as `Future`, because until the result is not set, there is nothing at its | ||
output. | ||
|
||
For taking advantage of all those *functionalities*, you just need to **subscribe you class** | ||
(that must implement `OnThreadCompletedListener`) to the correspondent `NotifyingThread`. If not, | ||
it is just a simple thread 🤷 | ||
|
||
------------------ | ||
|
||
```java | ||
import com.github.javinator9889.threading.threads.notifyingthread.*; | ||
|
||
public class NotifyingThreadExampleClass implements OnThreadCompletedListener { | ||
// Default constructor - we do not need anything else | ||
public NotifyingThreadExampleClass() {} | ||
|
||
public void executeAThread() { | ||
// Generate a new NotifyingThread | ||
// We are using a lambda expression for providing the | ||
// Runnable class; it is the same as doing: | ||
// | ||
// new NotifyingThread(new Runnable() { | ||
// @Override | ||
// public void run() { | ||
// System.out.println("Hi, I am a NotifyingThread"); | ||
// } | ||
// }); | ||
NotifyingThread thread = new NotifyingThread(() -> | ||
System.out.println("Hi, I am a NotifyingThread") | ||
); | ||
|
||
// Subscribe this class (NotifyingThreadExampleClass) | ||
// for getting notified whether the thread has finished | ||
// or it was interrupted by an exception | ||
thread.addOnThreadCompletedListener(this); | ||
|
||
// Setup a custom name for identification | ||
thread.setName("NotifyingThreadExample"); | ||
|
||
// Start executing - this is always necessary | ||
thread.start(); | ||
} | ||
|
||
// Custom implementation for knowing that a thread has finished | ||
// Here, we can wait until a concrete thread has finished for starting | ||
// another job that requires the thread that called "onThreadCompletedListener" | ||
// to finish. | ||
@Override | ||
public void onThreadCompletedListener(Thread thread, @Nullable Throwable exception) { | ||
switch (thread.getName()) { | ||
case "NotifyingThreadExample": | ||
System.out.println("NotifyingThread finished!"); | ||
if (exception != null) { | ||
System.err.println("NotifyingThread threw an exception during execution"); | ||
exception.printStackTrace(); | ||
} else { | ||
System.out.println("NotifyingThread finished without errors"); | ||
anotherThreadThatRequiresNotifyingThreadToFinish().start(); | ||
} | ||
break; | ||
default: | ||
System.err.println("Mmmmm"); | ||
break; | ||
} | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# Examples | ||
|
||
## 3. Using lambdas | ||
|
||
`Thread` does not allow us to **change its runnable** once it has been created, which is not a | ||
problem (is very strange to change that once a thread is created) but can be. | ||
|
||
If you have read the [documentation about NotifyingThread](https://javinator9889.github.io/ThreadingTools/com/github/javinator9889/threading/threads/notifyingthread/NotifyingThread.html), | ||
you have noticed that there are **four methods** for setting an executable *once the class is | ||
created*. Those methods are: | ||
|
||
+ `setExecutable(Runnable runnable)` | ||
+ `setExecutable(Consumer<ArgumentParser> consumer, ArgumentParser args)` | ||
+ `setExecutable(Function<ArgumentParser, ?> function, ArgumentParser args, AtomicReference result)` | ||
+ `setExecutable(Supplier supplier, AtomicReference result)` | ||
|
||
Those methods, taking advantage of **lambda expressions**, allows you to directly **refer to a | ||
method** and its arguments on a single line, with the following format: | ||
|
||
class::methodReference | ||
|
||
-------------- | ||
|
||
```java | ||
import com.github.javinator9889.threading.threads.notifyingthread.NotifyingThread; | ||
import com.github.javinator9889.utils.ArgumentParser; | ||
|
||
public class LambdasExampleClass { | ||
private int mFirstField; | ||
private String mSecondField; | ||
private ArrayList<HashMap<String, Integer>> mThirdField; | ||
|
||
// A constructor that initializes the class fields | ||
// All methods used are invented and they have no implementation | ||
public LambdasExampleClass() { | ||
mFirstField = getRandomValue(); | ||
mSecondField = getRandomString(); | ||
mThirdField = generateListOfMaps(); | ||
} | ||
|
||
public void runnableOperation() { | ||
// Operation that takes no arguments and return nothing | ||
System.out.println(mFirstField + mSecondField + mThirdField.toString()); | ||
} | ||
|
||
public void consumerOperation(ArgumentParser args) { | ||
int valueToConsume = args.getInt("value"); | ||
// Do something with the value, for example, assigning | ||
// "mFirstField" to the pow of that two values | ||
mFirstField = Math.pow(valueToConsume, mFirstField); | ||
} | ||
|
||
public String supplierOperation() { | ||
// Do something with the "mSecondField", for example, | ||
// appending current thread name | ||
return mSecondField + Thread.currentThread().getName(); | ||
} | ||
|
||
public List<Map<String, Integer>> functionOperation(ArgumentParser args) { | ||
int firstValue = args.getInt("firstParam"); | ||
int secondValue = args.getInt("secondParam"); | ||
String thirdValue = args.getString("thirdParam"); | ||
// Do something with the three params and the field | ||
// "mThirdField", for example, obtaining the keys | ||
// in which the value equals "firstValue" or "secondValue" | ||
// and changing it to the "thirdValue" | ||
List<Map<String, Integer>> result = new ArrayList(mThirdField.size()); | ||
for (Map<String, Integer> currentVal : mThirdField) { | ||
if (currentVal.containsValue(firstValue)) { | ||
// do the interchange | ||
} | ||
if (currentVal.containsValue(secondValue)) { | ||
// do the interchange | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
public void runFunctionsOnANewThread() { | ||
// First, we will generate a new NotifyingThread | ||
// for each function | ||
NotifyingThread first = new NotifyingThread(); | ||
NotifyingThread second = new NotifyingThread(); | ||
NotifyingThread third = new NotifyingThread(); | ||
NotifyingThread fourth = new NotifyingThread(); | ||
|
||
// Now, we need to create ArgumentParser objects | ||
// for our functions arguments. | ||
ArgumentParser consumerArgs = new ArgumentParser(); | ||
ArgumentParser functionArgs = new ArgumentParser(); | ||
|
||
// In addition, we need to create the AtomicReference | ||
// objects that will store the functions result | ||
AtomicReference<String> supplierResult = new AtomicReference<>(); | ||
AtomicReference<List<Map<String, Integer>>> functionResult = new AtomicReference<>(); | ||
|
||
// Finally, setup the params with their values | ||
consumerArgs.putParam("value", getRandomValue()); | ||
functionArgs.putParam("firstParam", getRandomValue()); | ||
functionArgs.putParam("secondParam", getRandomValue()); | ||
functionArgs.putParam("thirdParam", getRandomString()); | ||
|
||
// Now, use lambdas for setting the executables that are | ||
// going to be executed | ||
first.setExecutable(this::runnableOperation); | ||
second.setExecutable(this::consumerOperation, consumerArgs); | ||
third.setExecutable(this::supplierOperation, supplierResult); | ||
fourth.setExecutable(this::functionOperation, functionArgs, functionResult); | ||
|
||
// Start the threads | ||
first.start(); | ||
second.start(); | ||
third.start(); | ||
fourth.start(); | ||
|
||
// Wait for the threads to finish and work with the results | ||
System.out.println(supplierResult.get()); | ||
System.out.println(functionResult.get()); | ||
} | ||
} | ||
``` |
Oops, something went wrong.