What's the difference between deadlock and livelock?

后端 未结 7 1698
渐次进展
渐次进展 2021-01-29 17:20

Can somebody please explain with examples (of code) what is the difference between deadlock and livelock?

相关标签:
7条回答
  • 2021-01-29 17:53

    Maybe these two examples illustrate you the difference between a deadlock and a livelock:


    Java-Example for a deadlock:

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class DeadlockSample {
    
        private static final Lock lock1 = new ReentrantLock(true);
        private static final Lock lock2 = new ReentrantLock(true);
    
        public static void main(String[] args) {
            Thread threadA = new Thread(DeadlockSample::doA,"Thread A");
            Thread threadB = new Thread(DeadlockSample::doB,"Thread B");
            threadA.start();
            threadB.start();
        }
    
        public static void doA() {
            System.out.println(Thread.currentThread().getName() + " : waits for lock 1");
            lock1.lock();
            System.out.println(Thread.currentThread().getName() + " : holds lock 1");
    
            try {
                System.out.println(Thread.currentThread().getName() + " : waits for lock 2");
                lock2.lock();
                System.out.println(Thread.currentThread().getName() + " : holds lock 2");
    
                try {
                    System.out.println(Thread.currentThread().getName() + " : critical section of doA()");
                } finally {
                    lock2.unlock();
                    System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer");
                }
            } finally {
                lock1.unlock();
                System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer");
            }
        }
    
        public static void doB() {
            System.out.println(Thread.currentThread().getName() + " : waits for lock 2");
            lock2.lock();
            System.out.println(Thread.currentThread().getName() + " : holds lock 2");
    
            try {
                System.out.println(Thread.currentThread().getName() + " : waits for lock 1");
                lock1.lock();
                System.out.println(Thread.currentThread().getName() + " : holds lock 1");
    
                try {
                    System.out.println(Thread.currentThread().getName() + " : critical section of doB()");
                } finally {
                    lock1.unlock();
                    System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer");
                }
            } finally {
                lock2.unlock();
                System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer");
            }
        }
    }
    
    

    Sample output:

    Thread A : waits for lock 1
    Thread B : waits for lock 2
    Thread A : holds lock 1
    Thread B : holds lock 2
    Thread B : waits for lock 1
    Thread A : waits for lock 2
    

    Java-Example for a livelock:

    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class LivelockSample {
    
        private static final Lock lock1 = new ReentrantLock(true);
        private static final Lock lock2 = new ReentrantLock(true);
    
        public static void main(String[] args) {
            Thread threadA = new Thread(LivelockSample::doA, "Thread A");
            Thread threadB = new Thread(LivelockSample::doB, "Thread B");
            threadA.start();
            threadB.start();
        }
    
        public static void doA() {
            try {
                while (!lock1.tryLock()) {
                    System.out.println(Thread.currentThread().getName() + " : waits for lock 1");
                    Thread.sleep(100);
                }
                System.out.println(Thread.currentThread().getName() + " : holds lock 1");
    
                try {
                    while (!lock2.tryLock()) {
                        System.out.println(Thread.currentThread().getName() + " : waits for lock 2");
                        Thread.sleep(100);
                    }
                    System.out.println(Thread.currentThread().getName() + " : holds lock 2");
    
                    try {
                        System.out.println(Thread.currentThread().getName() + " : critical section of doA()");
                    } finally {
                        lock2.unlock();
                        System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer");
                    }
                } finally {
                    lock1.unlock();
                    System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer");
                }
            } catch (InterruptedException e) {
                // can be ignored here for this sample
            }
        }
    
        public static void doB() {
            try {
                while (!lock2.tryLock()) {
                    System.out.println(Thread.currentThread().getName() + " : waits for lock 2");
                    Thread.sleep(100);
                }
                System.out.println(Thread.currentThread().getName() + " : holds lock 2");
    
                try {
                    while (!lock1.tryLock()) {
                        System.out.println(Thread.currentThread().getName() + " : waits for lock 1");
                        Thread.sleep(100);
                    }
                    System.out.println(Thread.currentThread().getName() + " : holds lock 1");
    
                    try {
                        System.out.println(Thread.currentThread().getName() + " : critical section of doB()");
                    } finally {
                        lock1.unlock();
                        System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer");
                    }
                } finally {
                    lock2.unlock();
                    System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer");
                }
            } catch (InterruptedException e) {
                // can be ignored here for this sample
            }
        }
    }
    
    

    Sample output:

    Thread B : holds lock 2
    Thread A : holds lock 1
    Thread A : waits for lock 2
    Thread B : waits for lock 1
    Thread B : waits for lock 1
    Thread A : waits for lock 2
    Thread A : waits for lock 2
    Thread B : waits for lock 1
    Thread B : waits for lock 1
    Thread A : waits for lock 2
    Thread A : waits for lock 2
    Thread B : waits for lock 1
    ...
    

    Both examples force the threads to aquire the locks in different orders. While the deadlock waits for the other lock, the livelock does not really wait - it desperately tries to acquire the lock without the chance of getting it. Every try consumes CPU cycles.

    0 讨论(0)
提交回复
热议问题