Deadlock과 Livelock 쉽게 이해하기

KKTRKKT·2024년 5월 24일
0

쉽게 이해하기

목록 보기
4/4

교착상태(Deadlock)와 라이브락(Livelock)은 둘 다 다중 스레드나 프로세스가 상호작용하는 시스템에서 발생할 수 있는 문제입니다. 각각의 개념을 설명하고, 발생 원인 및 예시를 들어 이해를 돕겠습니다.

교착상태 (Deadlock)

정의

교착상태는 두 개 이상의 프로세스가 서로의 작업이 끝나기를 무한정 기다리며 아무런 작업도 진행하지 못하는 상태를 의미합니다. 이 상태에서는 각 프로세스가 다른 프로세스가 소유한 자원을 기다리기 때문에 진행이 불가능해집니다.

예시

두 스레드가 두 자원을 사용하려고 할 때 교착상태가 발생할 수 있습니다. 예를 들어, 두 스레드가 각각 자원 A와 자원 B를 필요로 하는 상황을 생각해봅시다.

public class DeadlockExample {
    static class Resource {
        private final String name;

        Resource(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }

    public static void main(String[] args) {
        final Resource resource1 = new Resource("Resource1");
        final Resource resource2 = new Resource("Resource2");

        Runnable task1 = () -> {
            synchronized (resource1) {
                System.out.println(Thread.currentThread().getName() + " locked " + resource1.getName());
                try { Thread.sleep(50); } catch (InterruptedException e) {}
                synchronized (resource2) {
                    System.out.println(Thread.currentThread().getName() + " locked " + resource2.getName());
                }
            }
        };

        Runnable task2 = () -> {
            synchronized (resource2) {
                System.out.println(Thread.currentThread().getName() + " locked " + resource2.getName());
                try { Thread.sleep(50); } catch (InterruptedException e) {}
                synchronized (resource1) {
                    System.out.println(Thread.currentThread().getName() + " locked " + resource1.getName());
                }
            }
        };

        new Thread(task1, "Thread-1").start();
        new Thread(task2, "Thread-2").start();
    }
}

설명

  • Thread-1resource1을 잠그고, 잠시 후에 resource2를 잠그려고 합니다.
  • Thread-2resource2를 잠그고, 잠시 후에 resource1을 잠그려고 합니다.
  • Thread-1resource2Thread-2에 의해 잠겨 있어서 기다려야 하고, 동시에 Thread-2resource1Thread-1에 의해 잠겨 있어서 기다려야 합니다.
  • 이 상황에서 두 스레드는 서로의 자원을 기다리며 무한정 대기 상태에 빠집니다. 이것이 교착상태입니다.

라이브락 (Livelock)

정의

라이브락은 두 개 이상의 프로세스가 서로 상대방이 진행할 수 있도록 양보하다가 무한정 대기 상태에 빠지는 것을 의미합니다. 이 경우 각 프로세스는 계속해서 상태를 바꾸지만, 유효한 작업을 수행하지 못합니다.

예시

두 스레드가 자원을 사용하려고 계속 양보하는 상황을 생각해봅시다.

public class LivelockExample {
    static class Resource {
        private final String name;
        private boolean inUse;

        Resource(String name) {
            this.name = name;
        }

        public synchronized void use() {
            while (inUse) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            inUse = true;
        }

        public synchronized void release() {
            inUse = false;
            notify();
        }

        public String getName() {
            return name;
        }
    }

    public static void main(String[] args) {
        final Resource resource1 = new Resource("Resource1");
        final Resource resource2 = new Resource("Resource2");

        Runnable task1 = () -> {
            while (true) {
                resource1.use();
                System.out.println(Thread.currentThread().getName() + " using " + resource1.getName());
                try { Thread.sleep(50); } catch (InterruptedException e) {}

                if (!resource2.inUse) {
                    resource2.use();
                    System.out.println(Thread.currentThread().getName() + " using " + resource2.getName());
                    resource1.release();
                    resource2.release();
                    break;
                }

                resource1.release();
                try { Thread.sleep(10); } catch (InterruptedException e) {}
            }
        };

        Runnable task2 = () -> {
            while (true) {
                resource2.use();
                System.out.println(Thread.currentThread().getName() + " using " + resource2.getName());
                try { Thread.sleep(50); } catch (InterruptedException e) {}

                if (!resource1.inUse) {
                    resource1.use();
                    System.out.println(Thread.currentThread().getName() + " using " + resource1.getName());
                    resource2.release();
                    resource1.release();
                    break;
                }

                resource2.release();
                try { Thread.sleep(10); } catch (InterruptedException e) {}
            }
        };

        new Thread(task1, "Thread-1").start();
        new Thread(task2, "Thread-2").start();
    }
}

설명

  • Thread-1resource1을 사용하려고 하지만 resource2가 사용 중인지 확인합니다.
  • 만약 resource2가 사용 중이면 resource1을 해제하고 잠시 대기합니다.
  • Thread-2도 마찬가지로 resource2를 사용하려고 하지만 resource1이 사용 중인지 확인합니다.
  • 만약 resource1이 사용 중이면 resource2를 해제하고 잠시 대기합니다.
  • 두 스레드는 계속해서 자원을 양보하고 다시 시도하지만, 서로 양보하는 동안 진전을 이루지 못합니다. 이것이 라이브락입니다.

요약

  • 교착상태(Deadlock): 두 스레드가 서로가 가진 자원을 기다리며 멈추는 상황. 아무런 작업도 진행되지 않음.
  • 라이브락(Livelock): 두 스레드가 서로 양보하려고 하면서 계속해서 상태를 바꾸지만 실제 작업은 진행되지 않는 상황.

이 두 가지 문제는 다중 스레드 환경에서 발생할 수 있으며, 적절한 설계와 같은 동기화 기법또는 ThreadLocal 등을 통해 방지할 수 있습니다.

profile
https://kktrkkt.github.io/

0개의 댓글