Livelock in Java multi-threading is a situation where two or more threads are acting on a response to an action of each other and not able to make any progress because of that.
How livelock is different from deadlock in Java multi-threading is that in case of deadlock threads get blocked whereas in case of livelock threads are active but busy responding to each other thus not making any progress.
Livelock Java example
Let’s see example of livelock in Java multi-threading to understand it. A classic example to explain livelock is a multi-threaded application to deposit and withdraw money from accounts with a provision to rollback the transaction if transaction doesn’t go through.
import java.util.concurrent.locks.ReentrantLock; public class LivelockDemo { public static void main(String[] args) { Account acct1 = new Account(101, 5000); Account acct2 = new Account(102, 7000); // Creating two threads Thread thread1 = new Thread(new Operation(acct1, acct2, 100)); Thread thread2 = new Thread(new Operation(acct2, acct1, 100)); thread1.start(); thread2.start(); } } class Account{ int acctNum; int balance; ReentrantLock lock = new ReentrantLock(); Account(int acctNum, int balance){ this.acctNum = acctNum; this.balance = balance; } /** * Method for depositing amount * @param amount * @return */ public boolean deposit(int amount){ System.out.println("In deposit method"); if(this.lock.tryLock()){ try { // Simulating some delay Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("deposit in " + this.acctNum + " for " + Thread.currentThread().getName()); this.balance = balance + amount; return true; } return false; } /** * Method for withdrawing amount * @param amount * @return */ public boolean withdraw(int amount){ System.out.println("In withdraw method"); if(this.lock.tryLock()){ try { // Simulating some delay Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("Withdrawn from " + this.acctNum + " for " + Thread.currentThread().getName()); this.balance = balance - amount; return true; } return false; } public boolean transact(Account targetAcct, int amount){ //System.out.println("In transact method " + targetAcct); boolean flag = false; // If you can withdraw from the source account and // deposit it into target account then only return true if(this.withdraw(amount) && targetAcct.deposit(amount)){ flag = true; }else{ // Rollback and deposit the withdrawn amount back in source account System.out.println("Failed to deposit in " + targetAcct.acctNum + " depositing back in account " + this.acctNum); this.deposit(amount); } return flag; } } class Operation implements Runnable{ Account sourceAccount; Account targetAccount; int amount; Operation(Account sourceAccount, Account targetAccount, int amount){ this.sourceAccount = sourceAccount; this.targetAccount = targetAccount; this.amount = amount; } @Override public void run() { sourceAccount.transact(targetAccount, amount); } }
Output
In withdraw method In withdraw method Withdrawn from 102 for Thread-1 In deposit method Withdrawn from 101 for Thread-0 In deposit method Failed to deposit in 101 depositing back in account 102 In deposit method Failed to deposit in 102 depositing back in account 101 In deposit method deposit in 102 for Thread-1 deposit in 101 for Thread-0
Here you can see that you have two threads where one is withdrawing amount from Account 101 and depositing it in 102 and the other thread is withdrawing amount from Account 102 and depositing it in 101. Threads are failing to complete the transaction because of not able to get the lock and rolling back the transaction.
In the above example transaction is not run in the loop so the threads make just one attempt, you can change the run method as follows and see how both threads keep trying and rolling back the transactions without making any real progress.
public void run() { while(!sourceAccount.transact(targetAccount, amount)){ continue; } }
If you run your code with these changes in run() method you will have to terminate your program to come out of the loop.
Output
In withdraw method In withdraw method Withdrawn from 101 for Thread-0 Withdrawn from 102 for Thread-1 In deposit method In deposit method Failed to deposit in 101 depositing back in account 102 In deposit method Failed to deposit in 102 depositing back in account 101 In deposit method deposit in 102 for Thread-1 In withdraw method deposit in 101 for Thread-0 In withdraw method Withdrawn from 101 for Thread-0 In deposit method Withdrawn from 102 for Thread-1 In deposit method Failed to deposit in 102 depositing back in account 101 In deposit method Failed to deposit in 101 depositing back in account 102 In deposit method deposit in 102 for Thread-1 In withdraw method deposit in 101 for Thread-0 In withdraw method Withdrawn from 102 for Thread-1 In deposit method Withdrawn from 101 for Thread-0 In deposit method Failed to deposit in 101 depositing back in account 102 In deposit method Failed to deposit in 102 depositing back in account 101 In deposit method deposit in 101 for Thread-0 In withdraw method deposit in 102 for Thread-1 In withdraw method Withdrawn from 101 for Thread-0 In deposit method Withdrawn from 102 for Thread-1 In deposit method
That's all for this topic Livelock in Java Multi-Threading. If you have any doubt or any suggestions to make please drop a comment. Thanks!
Related Topics
You may also like-
At one point it will come out of the livelock, right? Because there could be a scenario where thread-0 and thread-1 might execute withdraw() simultaneously and deposit() simultaneously.
ReplyDelete