In this article we will see an example of a worker thread. When a work thread is created and run, it loops and waits for the availability of a task to execute. Once a task is assigned, it comes out of the waiting loop and executes the task. After the task is run, it will again wait for a new task, it will periodically check for the availability of task every few milliseconds.“workerthread”
Task Thread Flow
A task thread is a responsible to execute a single task when assigned to it. Once executed, it is ready for another task. If we try to assign another task while it is still busy with the current task then it will throw an exception ‘Already running a task!’.
A task thread can be used as a single worker thread and one can create a pool of worker threads, this way we can take care of multiple tasks.
When a task thread is started, it waits in loop till a task is assigned. By default the task thread is in a state to consume tasks based on the run
atomic boolean. As long as this is true
the thread is always running. In the below diagram this is shown as the outer loop. The inner loop is based on whether there is a task available.
There are two important methods:
- Method
run(Runnable)
is called to assign a task to the thread for execution. Once assigned the lock is notified. - Method
stopTaskThread()
sets the flagrun
tofalse
. First the thread will come out of inner loop and then the outer loop.
TaskThread:
package com.javarticles.threads; import java.util.concurrent.atomic.AtomicBoolean; import static com.javarticles.threads.PrintUtil.*; public class TaskThread extends Thread { private AtomicBoolean run = new AtomicBoolean(true); private Runnable runnable; private final Object lock = new Object(); TaskThread() { super("TaskThread"); } public void run(Runnable newRunnable) { synchronized(lock) { print("Got the lock. Assign new task and notify task thread"); if(runnable != null) { throw new IllegalStateException("Already running a task!"); } runnable = newRunnable; lock.notifyAll(); } } public void stopTaskThread() { synchronized (lock) { print("Stop task thread"); run.set(false); } } public void run() { boolean ran = false; while (run.get()) { print("In task thread, look for new tasks"); synchronized (lock) { print("Got the lock. Check whether it needs to run any task"); try { waitForRunnable(); ran = executeRunnable(); } catch (Throwable exceptionInRunnable) { print("Error while executing the Runnable: " + exceptionInRunnable); } finally { cleanupRunnable(); if (ran) { ran = false; } } } } print("Task thread is down"); } private boolean executeRunnable() { if (runnable == null) { return false; } print("Got a new task to run"); print("Run the task"); runnable.run(); return true; } private void cleanupRunnable() { synchronized (lock) { print("Task execution over"); runnable = null; } } private void waitForRunnable() { while (runnable == null && run.get()) { print("No task, wait for 500ms and then check again"); try { lock.wait(500); } catch (InterruptedException e) { print("Task thread was interrupted." + e); } } } }
We want to print the thread name too so PrintUtil
class appends the thread name.
PrintUtil:
package com.javarticles.threads; public class PrintUtil { private static Thread t() { return Thread.currentThread(); } public static void print(String text) { System.out.println(t() + ":" + text); } }
In the main thread, we create instance of task thread an dstart it. Next we assign a task to the thread for execution. If we try to assign another task it is going to throw IllegalStateException
. Note if you want to execute multiple tasks then we need to maintain a pool of task threads. After waiting for few milliseconds we assign another task for execution. Next we wait for few more seconds and then stop the task thread. “workerthread”
SingleTaskThreadExample:
package com.javarticles.threads; import static com.javarticles.threads.PrintUtil.*; public class SingleTaskThreadExample { public static void main(String[] args) { TaskThread taskThread = new TaskThread(); taskThread.start(); taskThread.run(new Task()); try { taskThread.run(new Task()); } catch (IllegalStateException e) { print(e.toString()); } waitTime(1000); taskThread.run(new Task()); waitTime(3000); taskThread.stopTaskThread(); } private static void waitTime(long ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { print("Thread interrupted"); } } static class Task implements Runnable { static int i = 0; Task() { i++; } public void run() { print("Task" + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
The output below is self explanatory.
Output:
Thread[main,5,main]:Got the lock. Assign new task and notify task thread Thread[TaskThread,5,main]:In task thread, look for new tasks Thread[main,5,main]:Got the lock. Assign new task and notify task thread Thread[TaskThread,5,main]:Got the lock. Check whether it needs to run any task Thread[main,5,main]:java.lang.IllegalStateException: Already running a task! Thread[TaskThread,5,main]:Got a new task to run Thread[TaskThread,5,main]:Run the task Thread[TaskThread,5,main]:Task2 Thread[TaskThread,5,main]:Task execution over Thread[TaskThread,5,main]:In task thread, look for new tasks Thread[main,5,main]:Got the lock. Assign new task and notify task thread Thread[TaskThread,5,main]:Got the lock. Check whether it needs to run any task Thread[TaskThread,5,main]:Got a new task to run Thread[TaskThread,5,main]:Run the task Thread[TaskThread,5,main]:Task3 Thread[TaskThread,5,main]:Task execution over Thread[TaskThread,5,main]:In task thread, look for new tasks Thread[TaskThread,5,main]:Got the lock. Check whether it needs to run any task Thread[TaskThread,5,main]:No task, wait for 500ms and then check again Thread[TaskThread,5,main]:No task, wait for 500ms and then check again Thread[TaskThread,5,main]:No task, wait for 500ms and then check again Thread[TaskThread,5,main]:No task, wait for 500ms and then check again Thread[main,5,main]:Stop task thread Thread[TaskThread,5,main]:Task execution over Thread[TaskThread,5,main]:Task thread is down
Download the source code “workerthread”
This was an example about a worker thread to execute tasks.