Java wait and notify Example

0

 

In this article, we will see how to make use of wait and notify mechanism to assign task to a worker thread. In case of thread pool, we start all the worker threads where each worker thread is waiting for a task. Moment a task is assigned, the work thread comes out of waiting, executes the task and goes back to the waiting state.

The main processing thread contain an outer loop and an inner loop. The inner loop waits for a task to be assigned. It checks for the task every few milliseconds. If there is no task assigned yet it simply waits on a lock object. Once a task is assigned, the lock object is notified so that it comes out of the sleep, and the inner loop to run the task. The outer loop contains the inner loop so after the task is executed, the thread goes back to waiting till next task is assigned.

Worker thread

Worker thread contains an outer loop and inner loop. The outer loop keeps running as long as the thread is not explicitly stopped. The inner loop makes sure that the thread waits till a task is assigned.

public void run() {
        while (!stopped.get()) {
...
                synchronized (lock) {
                    while (taskRunnable == null && !stopped.get()) {
                        ...
                    }
                }
...            
        }
    }
}

Wait on a lock object till the task is not assigned. Moment a task is assigned, the lock is notified so it comes out of the waiting and then executes the task.

while (taskRunnable == null && !stopped.get()) {
    try {
        ...
        lock.wait(500);
    } catch (InterruptedException e) {
    }
    if (taskRunnable != null) {                            
        taskRunnable.run();
    }
}

Assign a task and notify the lock object.

    public void runOnThread(Runnable newRunnable) {
        synchronized (lock) {
            ...
            taskRunnable = newRunnable;
            ...
            lock.notifyAll();
        }
    }

In order to stop the worker thread, set the stopped atomic boolean flag to true and notify the lock object. This will make the worker thread come out of the outer loop.

    public void stopTaskThread() {
        synchronized (lock) {
            stopped.set(true);
            lock.notifyAll();
        }
    }

Here is the complete worker thread.

TaskThread:

package com.javarticles.threads;

import java.util.concurrent.atomic.AtomicBoolean;

public class TaskThread extends Thread {
    private final Object lock = new Object();
    private AtomicBoolean stopped;
    private Runnable taskRunnable = null;

    public TaskThread(String threadName) {
        super(threadName);
        stopped = new AtomicBoolean(false);
        setDaemon(false);
    }

    public void stopTaskThread() {
        synchronized (lock) {
            stopped.set(true);
            lock.notifyAll();
        }
    }

    public void runOnThread(Runnable newRunnable) {
        synchronized (lock) {
            if (taskRunnable != null) {
                throw new IllegalStateException("Already running a Runnable!");
            }

            taskRunnable = newRunnable;
            PrintUtils.print("Assign " + taskRunnable);
            lock.notifyAll();
        }
    }

    public void run() {
        while (!stopped.get()) {
            try {
                synchronized (lock) {
                    while (taskRunnable == null && !stopped.get()) {
                        try {
                            System.out.print(".");
                            lock.wait(500);
                        } catch (InterruptedException e) {
                        }
                        if (taskRunnable != null) {                            
                            taskRunnable.run();
                        }
                    }
                }
            } catch (Exception e) {
                PrintUtils.print("Exception trying to run " + taskRunnable + "\n" + e);
            } finally {
                synchronized (lock) {
                    taskRunnable = null;
                }
            }

        }
    }
}

The example is only about how we can use wait and notify in a worker thread so for simplicity case we have used only a single worker thread. Class Task represents a task. We start the worker thread first and then assign a task to it. We next sleep for few seconds and then assign next task. Finally, we stop the worker thread.

TaskRunnerExample:

package com.javarticles.threads;

public class TaskRunnerExample {
    public static void main(String[] args) throws InterruptedException {
        TaskThread taskThread = new TaskThread("TaskThread");
        taskThread.start();
        Thread.sleep(3000);
        taskThread.runOnThread(new Task(1));
        Thread.sleep(5000);
        taskThread.runOnThread(new Task(2));
        Thread.sleep(7000);
        System.out.println("\nStop task thread");
        taskThread.stopTaskThread();
    }

    static class Task implements Runnable {
        int i;

        Task(int i) {
            this.i = i;
        }

        public void run() {
            PrintUtils.print("Running " + this);
        }

        public String toString() {
            return "Task(" + i + ")";
        }
    }
}

PrintUtils:

package com.javarticles.threads;

public class PrintUtils {
    public static void print(String s) {
        System.out.println(Thread.currentThread().getName() + ":" + s);
    }
}

Output:

.......main:Assign Task(1)
TaskThread:Running Task(1)
..........main:Assign Task(2)
TaskThread:Running Task(2)
...............
Stop task thread

Download the source code

This was an example about assigning tasks to a task running thread that wakes up as soon as a task is assigned.

You can download the source code here: javaTaskRunnerExample.zip

About Author

Ram’s expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring.
You can reach him at [email protected]

Comments are closed.