자바 병렬프로그래밍[10] 활동성을 최대로 높이기

kimji1
3 min readApr 6, 2020

--

데드락

식사하는 철학자

테이블에는 다섯 개의 젓가락(다섯 쌍 X)이 개인별 접시 사이에 하나씩 놓여 있다. 
철학자는 '먹는' 동작과 '생각하는'동작을 차례대로 반복한다.
접시 양 쪽에 있는 두 개를 모아 한 쌍의 젓가락을 만들어야 자신의 접시에 놓인 음식을 먹을 수 있고 음식을 먹은 이후에는 젓가락을 다시 양쪽에 하나씩 내려 놓고 생각을 시작한다.모든 철학자가 각자 자기 왼쪽에 있는 젓가락을 집은 다음 오른쪽 젓가락을 사용할 때까지 기다렸다가 오른쪽 젓가락을 집어서 식사를 한다면, 모든 철학자가 더 이상 먹지 못하는 상황에 다다를 수 있다. 철학자 모두가 먹지 못하는 상황은 음식을 먹는 데 필요한 자원을 모두 다른 곳에서 확보하고 놓지 않기 때문에 모두가 서로 상대방이 자원을 놓기만을 기다리는 이른바 데드락이 걸린다.
  • 스레드가 사이클을 이루면 상대방이 확보한 락을 얻으려 대기하는 상태의 데드락이 자주 발생한다.
  • directed graph를 예로 들면 그래프의 노드는 스레드 하나를 의미하고, 그래프의 엣지는 ‘스레드 B가 확보한 독점 자원을 스레드 A가 가져가려고 대기하는 상태'를 나타낸다. 만약 이런 directed graph에서 사이클이 나타난다면 데드락이 발생하는 것과 동일

락 순서에 의한 데드락

  • 프로그램 내부의 모든 스레드에서 필요한 락을 모두 같은 순서로만 사용한다면, 락 순서에 의한 데드락은 발생하지 않음

동적인 락 순서에 의한 데드락

객체에 순서를 부여할 수 있는 방법

  • System.identityHashCode메서드를 사용하여 Object.hashCode 메서드를 호출했을 때의 값을 얻음
  • 두 개의 객체가 같은 hash 코드를 사용하는 경우 타이 브레이킹 락 사용
  • 락을 확보하기 전에 타이 브레이킹 락을 확보하며, 타이 브레이킹 락을 확보한다는 것은 두 개의 락을 임의의 순서로 확보하는 위험한 작업을 특정 순간에 하나의 스레드에서만 할 수 있도록 막는다는 의미
  • hashCode가 동일한 값을 갖는 경우가 자주 발생한다면 타이 브레이킹 락을 확보하는 부분이 일종의 병목으로 작용할 가능성도 있음

오픈 호출

  • 락을 전혀 확보하지 않은 상태에서 메서드를 호출하는 것
  • 오픈 호출로만 이뤄진 클래스는 락을 확보한 채로 메서드를 호출하는 클래스보다 훨씬 안정적이며 다른 곳에서 불러다 쓰기도 좋음
  • 오픈 호출을 사용하는 것은 스레드 안전성을 확보하기 위해 캡슐화 기법을 사용하는 것과 비슷

다른 활동성 문제들

리소스 데드락

  • 스레드가 서로 상대방이 이미 확보하고 앞으로 놓지 않을 락을 기다리느라 서로 데드락에 빠질 수 있는 것처럼, 필요한 자원을 사용하기 위해 대기하는 과정에 발생
  • 스레드 부족 데드락, 현재 실행 중인 작업이 또 다른 작업을 큐에 쌓고 그 작업이 끝날 때까지 대기하는 데드락 상황

Starvation(소모)

  • 스레드가 작업을 진행하는 데 꼭 필요한 자원을 영영 할당받지 못하는 경우에 발생
  • 스레드 우선 순위를 적절하지 못하게 올리거나 내리는 부분이 흔한 원인
  • 락을 확보한 채로 종료되지 않는 코드를 실행할 때, 다른 스레드에서 해당 락을 가질 수 없기 때문에 소모 상황 발생

라이브락

  • 대기 중인 상태가 아니었다 해도 특정 작업의 결과를 받아와야 다음 단계로 넘어갈 수 있는 작업이 실패할 수 밖에 없는 기능을 계속해서 재시도 하는 경우에 쉽게 발생
  • 여러 스레드가 함께 동작하는 환경에서 각 스레드가 다른 스레드의 응답에 따라 각자의 상태를 계속해서 변경하느라 실제 작업은 전혀 진전시키지 못하는 경우에 발생하기도 함

--

--

kimji1
kimji1

No responses yet