What is live lock and hunger?

Posted by KeitaroHimura on Wed, 16 Oct 2019 14:57:20 +0200

Life lock

The task is not blocked. Because some conditions are not met, the process of try fail try fail is repeated all the time. The entity in the live lock is constantly changing, and the live lock may be released by itself.

Deadlock is that everyone can't get the resources and occupy each other's resources, while live lock is to get the resources and release each other.

 

A simple way to solve the livelock is to sleep for a short period of time at random before the next attempt to acquire resources.

 

Take a look at our previous example. If we do not sleep randomly at last, life locks will be generated. The phenomenon is that for a long time, two threads are constantly trying to acquire and release locks.

package constxiong.concurrency.a023;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * When the thread that occupies part of the resources further applies for other resources, if the application fails, it will actively release the resources it occupies and destroy the "non preemptive" condition.
 * @author ConstXiong
 * @date 2019-09-24 14:50:51
 */
public class TestBreakLockOccupation {
	
	private static Random r = new Random(); 

	private static Lock lock1 = new ReentrantLock();
	
	private static Lock lock2 = new ReentrantLock();
	
	public static void main(String[] args) {
		new Thread(() -> {
			//Identify whether the task is completed
			boolean taskComplete = false;
			while (!taskComplete) {
				lock1.lock();
				System.out.println("Threading:" + Thread.currentThread().getName() + " Get lock lock1 Success");
				try {
					//Sleep at random to help create a deadlock environment
					try {
						Thread.sleep(r.nextInt(30));
					} catch (Exception e) {
						e.printStackTrace();
					}
					
					//Thread 0 tried to get lock2
					if (lock2.tryLock()) {
						System.out.println("Threading:" + Thread.currentThread().getName() + " Get lock lock2 Success");
						try {
							taskComplete = true;
						} finally {
							lock2.unlock();
						}
					} else {
						System.out.println("Threading:" + Thread.currentThread().getName() + " Get lock lock2 fail");
					}
				} finally {
					lock1.unlock();
				}
				
				//Sleep randomly to avoid live lock
				try {
					Thread.sleep(r.nextInt(10));
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		new Thread(() -> {
			//Identify whether the task is completed
			boolean taskComplete = false;
			while (!taskComplete) {
				lock2.lock();
				System.out.println("Threading:" + Thread.currentThread().getName() + " Get lock lock2 Success");
				try {
					//Sleep at random to help create a deadlock environment
					try {
						Thread.sleep(r.nextInt(30));
					} catch (Exception e) {
						e.printStackTrace();
					}
					
					//Thread 2 attempts to acquire lock lock1
					if (lock1.tryLock()) {
						System.out.println("Threading:" + Thread.currentThread().getName() + " Get lock lock1 Success");
						try {
							taskComplete = true;
						} finally {
							lock1.unlock();
						}
					} else {
						System.out.println("Threading:" + Thread.currentThread().getName() + " Get lock lock1 fail");
					}
				} finally {
					lock2.unlock();
				}
				
				//Sleep randomly to avoid live lock
				try {
					Thread.sleep(r.nextInt(10));
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
	
}

 

hunger

A thread can't get CPU running time because all CPU time is preempted by other threads, so the thread can't execute.

Causes of hunger:

  • Priority thread consumes CPU time of all low priority threads
  • Other threads can always access the synchronization block before it, and the thread is permanently blocked in a waiting block.
  • Other threads are always preempted and continuously awakened. Threads are always waiting to be awakened.
package constxiong.concurrency.a024;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Test thread hunger
 * @author ConstXiong
 */
public class TestThreadHungry {

	private static ExecutorService es = Executors.newSingleThreadExecutor();
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		Future<String> future1 = es.submit(new Callable<String>() {
			@Override
			public String call() throws Exception {
				System.out.println("Submit task 1");
				Future<String> future2 = es.submit(new Callable<String>() {
					@Override
					public String call() throws Exception {
						System.out.println("Submit task 2");
						return "Task 2 Results";
					}
				});
				return future2.get();
			}
		});
		System.out.println("Get to" + future1.get());
	}
	
}

 

The print result is as follows, the thread pool is stuck. The thread pool can only hold one task, task 1 submits task 2, and task 2 can never be executed.

Submit task 1


       

Java interview question summary, there is always a stuck you!

Topics: Programming Java