Introduction
Sometimes it may be necessary to use Threads. One of the most obvious scenarios is when you have two processes that have to take place at the "same-time". Take for instance loading a web-page inside a web-browser. There is the time-consuming process, of actually loading the HTML, parsing it, then loading the images and any other resources the web-page requires. Then, there is the process of updating the browser's GUI with some progress-indicator, and perhaps rendering the web-page's content while it's being loaded. When the time-consuming process is complete, the browser has to finish rendering the whole page and activate any interactive elements thus transferring control back to the user.
ThreadAction
The ThreadAction
class is intended to solve exactly this. By extending the ThreadAction
class, you must override three methods which correspond to the three parts of the scenario:
- The time-consuming-process that has to be completed.
- A short repeatable process that usually is meant to update the User with the progression of the first process.
- A process that is activated once the first process completes, thus finishing the whole cycle.
Java Code
public abstract class ThreadAction implements Runnable {
private int actionProgressSleep;
private boolean actionFinished;
private boolean actionPerforming;
private Thread actionRunner;
private Thread actionProgress;
protected ThreadAction() {
reset();
}
protected Thread getThread(String name) {
return new Thread(this, name);
}
public void reset() {
actionProgressSleep = 300;
actionFinished = true;
actionPerforming = false;
actionRunner = null;
actionProgress = null;
}
public void setActionProgressSleep(int sleepTime) {
if (!isActionPerforming()) {
reset();
actionProgressSleep = sleepTime;
}
}
public void run() {
if (actionRunner == Thread.currentThread()) {
performAction();
actionPerforming = false;
} else if (actionProgress == Thread.currentThread()) {
while (actionPerforming) {
whilePerformingAction();
try {
Thread.currentThread().sleep(actionProgressSleep);
} catch (Exception ex) {
}
}
whenActionFinished();
actionRunner = null;
actionProgress = null;
actionFinished = true;
synchronized (this) {
notifyAll();
}
}
}
public void activateAction(boolean waitForAction) {
if (!isActionPerforming()) {
if (actionProgress == null) {
actionProgress = getThread("ActionProgressUpdateThread");
}
if (actionRunner == null) {
actionRunner = getThread("ActionRunnerThread");
}
actionFinished = false;
actionPerforming = true;
actionProgress.start();
actionRunner.start();
if (waitForAction) {
waitForAction();
}
}
}
public void waitForAction() {
if (isActionPerforming()) {
synchronized (this) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
public boolean isActionPerforming() {
return actionPerforming || (!actionFinished);
}
public abstract void performAction();
public abstract void whilePerformingAction();
public abstract void whenActionFinished();
}
Testing the Code
We can add a main(..)
method to the ThreadAction
class, or add it in a different class altogether, to test how ThreadAction
actually works:
public static void main(String[] args) {
ThreadAction ta = new ThreadAction() {
public void performAction() {
long time = System.currentTimeMillis() + 600;
while (time > System.currentTimeMillis()) {
System.out.println("| X | | |");
try {
Thread.sleep(250);
} catch (InterruptedException ex) {
}
}
}
public void whilePerformingAction() {
System.out.println("| | X | |");
}
public void whenActionFinished() {
System.out.println("| | | X |");
}
};
ta.setActionProgressSleep(200);
System.out.println("+---------+----------+----------+");
System.out.println("| Working | Updating | Complete |");
System.out.println("+---------+----------+----------+");
ta.activateAction(true);
System.out.println("+---------+----------+----------+");
}
As you can see, the main(..)
method defines an inner class extending ThreadAction
and overrides the abstract
methods with simple implementation that will print out an 'X
' character corresponding to whatever the method is supposed to be doing at the time.
The output, on my machine, looks like this:
+---------+----------+----------+
| Working | Updating | Complete |
+---------+----------+----------+
| | X | |
| X | | |
| | X | |
| X | | |
| | X | |
| X | | |
| | X | |
| | | X |
+---------+----------+----------+
Please notice the activation of the ThreadAction
with the value of True
sent to the activateAction(..)
method. If we were to invoke activateAction(..)
with False
instead, the printing from the main
Thread would have occurred before our ThreadAction
could have started.
If you have not activated the ThreadAction
with True
specified in activateAction(..)
and you want to wait for the ThreadAction
to complete its course, you can use the waitForAction()
method at any time before the ThreadAction
is done.
I have used this class in my applications for many scenarios, logging-in, fetching complex data from a database, anything where a background process has to take place beside a time-consuming one.
Another Example
The following code demonstrates using ThreadAction
in a log-in process:
public class LoginAction extends ThreadAction {
public String userName;
public String passWord;
public String networkResource;
private boolean loginFailed;
private int errorCode;
public void performAction() {
}
public void whilePerformingAction() {
}
public void whenActionFinished() {
}
}
Please note that ThreadAction
is designed so that its instances can be used repeatedly within the life cycle of an application, and also in such a way that enables using a Thread-Pool class to provide the Threads instead of re-creating them each time the activateAction(..)
method is invoked.
Hope this one helps you and happy coding.