Busy Waiting or Spinning Example in Java Multi-threading

What is busy waiting or spinning? Busy spinning or waiting in multi-threading environment is a technique in which a process repeatedly checks if a particular condition is true instead of wait() or sleep() method and without releasing the CPU.

In other words busy spinning is one of the techniques to wait for events without releasing CPU.

Busy waiting or spinning is mainly useful in multi-core processors where a condition becomes true quickly, i.e., in milliseconds or microseconds or even in nanoseconds.

One of the advantages of busy waiting is avoid losing CPU cached data, which may be lost if the thread is paused in one core and resumed in another core.

Is there any issue or busy waiting bad? A normal programming running on normal operating system does not have clue about which threads run on which processors, even a normal operating system does not have any way to know the difference between a thread that is busy waiting and a thread that is doing work.

Even if the operating system knows a thread was busy waiting or spinning then also it is not known to operating system, why the thread was waiting.

It’s actually bad when there are some ready-to-run threads and one of the ready-to-run threads is busy waiting in a loop for a condition to be met. Another reason to consider it as bad from performance standpoint as it consumes resources due to it is just busy waiting on a loop.

Where it may be useful? If you are working on low latency system where your order processing thread currently doesn’t have any order, instead of calling sleep() or wait() method, you can just loop through and again check the queue for new message(s). It’s only beneficial if you need to wait for a very small amount of time, i.e., in microseconds or nanoseconds.

Sometimes it is necessary to write some sort of control data to hardware and then fetch device status resulting from the write operation, status that may not become valid until a number of machine cycles have elapsed following the write. The programmer could call an operating system delay function, but doing so may consume more time than would be expended in spinning for a few clock cycles waiting for the device to return its status (Wikipedia).

Can we avoid busy waiting or spinning? To avoid such situation we can use wait() and notify() methods. The wait() method will let the thread release the CPU and wait for notify() method to get signal by other thread once the other thread finished its tasks. This way we can avoid unnecessary consumption of CPU resources.

Let’s create an example on busy waiting in Java programming language.

We are going to show you this example with producer consumer problem. When producer is producing data, consumer is repeatedly checks the condition, i.e., in our case a boolean flag set on producer. If this flag is false then only consumer starts consumer data produced by producer otherwise consumer is waiting on busy producer.

Producer

package com.roytuts.java.busy.waiting.spinning;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class Producer implements Runnable {

	private volatile boolean isBusy;
	private List<String> uuidList;

	public Producer() {
		this.isBusy = true;
		this.uuidList = new ArrayList<>();
	}

	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
			String uuid = UUID.randomUUID().toString();

			System.out.println("Producing UUID: " + uuid);

			uuidList.add(uuid);
		}

		isBusy = false;
	}

	public boolean isBusy() {
		return isBusy;
	}

	public List<String> getUuidList() {
		return uuidList;
	}

}

Consumer

package com.roytuts.java.busy.waiting.spinning;

import java.util.Iterator;

public class Consumer implements Runnable {

	private Producer producer;

	public Consumer(Producer producer) {
		this.producer = producer;
	}

	@Override
	public void run() {
		while (producer.isBusy()) {
			System.out.println("Producer busy... Consumer waiting...");
		}

		System.out.println("Consumer started consuming");

		Iterator<String> it = this.producer.getUuidList().iterator();

		while (it.hasNext()) {
			String uuid = it.next();

			System.out.println("Consumed UUID: " + uuid);

			it.remove();
		}
	}

}

Testing the Program

package com.roytuts.java.busy.waiting.spinning;

public class BusyWaitingSpinningApp {

	public static void main(String[] args) {
		Producer p = new Producer();

		(new Thread(p, "Producer")).start();
		(new Thread(new Consumer(p), "Consumer")).start();
	}

}

Running the above program will give you the following output in the console:

...
Producer busy... Consumer waiting...
Producer busy... Consumer waiting...
Producing UUID: 0d3bdbb4-1645-49c1-a521-1b8a13c0b781
Producer busy... Consumer waiting...
Producer busy... Consumer waiting...
...
Producer busy... Consumer waiting...
Producer busy... Consumer waiting...
Producing UUID: 0f67b178-f5e1-4730-8267-ef6370371803
Producer busy... Consumer waiting...
Producer busy... Consumer waiting...
...
Producer busy... Consumer waiting...
Producer busy... Consumer waiting...
Producing UUID: be9a3267-f274-4017-80e0-ef3c1b44a11e
Producer busy... Consumer waiting...
Producer busy... Consumer waiting...
...
Producer busy... Consumer waiting...
Producer busy... Consumer waiting...
Producing UUID: 505c0e89-a199-4f30-874a-5a3dceb9e7fb
Producer busy... Consumer waiting...
Producer busy... Consumer waiting...
...
Producer busy... Consumer waiting...
Producer busy... Consumer waiting...
Producing UUID: 665428d2-3de1-4dd2-b42b-7fbcecf9eafb
Producer busy... Consumer waiting...
Consumer started consuming
Consumed UUID: 0d3bdbb4-1645-49c1-a521-1b8a13c0b781
Consumed UUID: 0f67b178-f5e1-4730-8267-ef6370371803
Consumed UUID: be9a3267-f274-4017-80e0-ef3c1b44a11e
Consumed UUID: 505c0e89-a199-4f30-874a-5a3dceb9e7fb
Consumed UUID: 665428d2-3de1-4dd2-b42b-7fbcecf9eafb

If you want to avoid such situation then you can use wait(), notify() methods.

Source Code

Download

Thanks for reading.

Leave a Comment