Livelock

Imagine you’re talking with your friend on your mobile phone and the call drops. You try to reconnect with her, but her phone is busy (because she’s trying to call you!). You wait for a few moments and try to reconnect, only to discover that her phone is still busy, because she waited for exactly the same duration before trying to reconnect again. If you compare yourself and your friend with threads, you both are in a livelock. You and your friend aren’t blocked—both of you are responding but aren’t being able to do what you both intend to (talk with each other).

Threads in a livelock aren’t blocked; they’re responding to each other, but they aren’t able to move to completion.

Because a livelock depends on the exact time of execution of threads, the same set of threads might not always livelock.

Livelock describes situation where two threads are busy responding to actions of each other. They keep repeating a particular code so the program is unable to make further progress:

Thread 1 acts as a response to action of thread 2

Thread 2 acts as a response to action of thread 1

Unlike deadlock, threads are not blocked when livelock occurs. They are simply too busy responding to each other to resume work. In other words, the program runs into an infinite loop and cannot proceed further.

A Livelock Example:

1)

Let’s see an example: a criminal kidnaps a hostage and he asks for ransom in order to release the hostage. A police agrees to give the criminal the money he wants once the hostage is released. The criminal releases the hostage only when he gets the money. Both are waiting for each other to act first, hence livelock.

Here’s the code of this example.

Criminal class:

package com.gs.iilp.corejava.threads;

class Criminal {
	private boolean hostageReleased = false;

	public boolean isHostageReleased() {
		return hostageReleased;
	}

	public void releaseHostage(Police police) {
		while (!police.isMoneySent()) {

			System.out.println("Criminal: waiting police to give ransom");

			try {
				Thread.sleep(1000);
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		}

		System.out.println("Criminal: released hostage");

		this.hostageReleased = true;
	}

}

class Police {
	private boolean moneySent = false;

	public boolean isMoneySent() {
		return moneySent;
	}

	public void giveRansom(Criminal criminal) {

		while (!criminal.isHostageReleased()) {

			System.out.println("Police: waiting criminal to release hostage");

			try {
				Thread.sleep(1000);
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		}

		System.out.println("Police: sent money");

		this.moneySent = true;
	}

}

public class HostageRescueLiveLock {

	static final Police police = new Police();

	static final Criminal criminal = new Criminal();

	public static void main(String[] args) {
		new Thread(() -> {
			police.giveRansom(criminal);
		}).start();

		new Thread(() -> {
			criminal.releaseHostage(police);
		}).start();
	}

}

2)

package com.gs.corejava.threads;

class Person_1 {

	private boolean isBusy;

	public boolean isBusy() {
		return isBusy;
	}

	public void makeCall(Person_2 person_2) {
		while (!person_2.isBusy()) {
			System.out.println("Person 1 is calling Person 2 ...");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		// person 1 is free now
		isBusy = true;
	}
}

class Person_2 {
	private boolean isBusy;

	public boolean isBusy() {
		return isBusy;
	}

	public void makeCall(Person_1 person_1) {
		while (!person_1.isBusy()) {
			System.out.println("Person 2 is calling Person 1 ...");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// person 2 is free now
		isBusy = true;
	}
}

public class LiveLockExample1 {

	static final Person_2 PERSON_2 = new Person_2();
	static final Person_1 PERSON_1 = new Person_1();

	public static void main(String[] args) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				PERSON_1.makeCall(PERSON_2);
			}
		}).start();
		new Thread(new Runnable() {

			@Override
			public void run() {
				PERSON_2.makeCall(PERSON_1);
			}
		}).start();
	}
}

Last updated