*<클린 코드>를 참고하여 작성한 글입니다.
- 동시성이 필요한 이유?
- 동시성은 결합을 없애는 전략이다. 즉, 무엇과 언제를 분리하는 전략이다. 스레드가 하나인 프로그램은 무엇과 언제가 서로 밀접하다. 하지만 이를 분리하면 어플리케이션 구조와 효율이 극적으로 나아진다. 구조적 관점에서 프로그램은 거대한 루프 하나가 아니라 작은 협력 프로그램 여럿으로 보인다. 따라서 시스템을 이해하기도, 문제를 분리하기도 쉽다.
- 동시성이 반드시 필요한 상황이 있지만, 어렵다. 각별히 주의하지 않으면 난감한 상황에 처한다.
- 동시성은 다소 부하를 유발한다 .성능 측면에서 부하가 걸리며, 코드도 더 짜야 한다.
- 동시성은 복잡하다. 간단한 문제라도 동시성은 복잡하다.
- 일반적으로 동시성 버그는 제현하기 어렵다. 그래서 진짜 결함으로 간주되지 않고 일회성 문제로 여겨 무시하기 쉽다.
- 동시성을 구현하려면 흔히 근본적인 설계 전략을 재고해야 한다.
- 동시성 방어 원칙
- SRP : 동시성 관련 코드는 다른 코드와 분리해야 한다.
- 따름 정리 - 자료 범위를 제한하라 : 공유 객체를 사용하는 코드 내 임계영역을 synchronized 키워드로 보호한다. 이런 임계 영역의 수를 줄이는 기술이 중요하다. 즉, 자료를 캡슐화하고 공유 자료를 최대한 줄여야 한다.
- 따름 정리 - 자료 사본을 사용하라 : 처음부터 공유하지 않는 방법이 좋다. 객체를 복사해 읽기 전용으로 사용하는 식이다. 사본으로 동기화를 피할 수 있다면 내부 잠금을 없애 절약한 수행 시간이 사본 생성과 가비지 컬렉션에 드는 부하를 상쇄할 가능성이 크다.
- 따름 정리 - 스레드는 가능한 독립적으로 구현하라 : 자신만의 세상에 존재하는 스레드를 구현한다. 즉, 다른 스레드와 자료를 공유하지 않으며 각 스레드는 클라이언트 요청 하나를 처리한다. 모든 정보는 비공유 출처에서 가져오며 로컬 변수에 저장한다. 그러면 각 스레드는 세상에 자신만 있는 듯이 돌아갈 수 있다.
- 라이브러리를 이해하라 : 동시성 측면에서 스레드 코드 구현 시 고려할 방안
- 스레드 환경에 안전한 컬렉션 사용
- 서로 무관한 작업을 수행할때는 executor 프레임워크 사용
- 가능하다면 스레드가 차단(block)되지 않는 방법을 사용
- 일부 클래스 라이브러리는 스레드에 안전하지 못함
- 실행 모델을 이해하라
- 한정된 자원(Bound Resource) : 길이가 일정한 읽기/쓰기 버퍼 등
- 상호 배제(Mutual Exclusion)
- 기아(Starvation)
- 데드락(Deadlock) : 여러 스레득 서로 끝나기를 기다림.
- 라이브락(Livelock) : 락을 거는 단계에서 각 스레드가 서로를 방해.
- 이에따른 실행 모델 1)생산자-소비자, 2)읽기-쓰기, 3)식사하는 철학자들
- 동기화하는 메서드 사이에 존재하는 의존성을 이해하라 : 공유 객체 하나에는 메서드 하나만 사용하라. 메서드 여러개가 필요할 경우 1)클라이언트에서 잠금 2)서버에서 잠금 3)연결 서버 세 가지 방법을 고려한다.
- 동기화하는 부분을 작게 만들어라
- 올바른 종료 코드는 구현하기 어렵다
- 스레드 코드 테스트하기 : 1)말이 안 되는 실패는 잠정적인 스레드 문제로 취급 2)다중 스레드를 고려하지 않은 순차 코드부터 제대로 돌게 만들 것 3) 다중 스레드를 쓰는 코드 부분을 다양한 환경에 쉽게 끼워넣을 수 있도록 스레드 코드 구현 4)다중 스레드를 쓰는 코드 부분을 상황에 맞춰 조정할 수 있게 작성 5)프로세서 수보다 많은 스레드를 돌려볼 것 6)다른 플랫폼에서 돌려볼 것 7)코도에 보조 코드를 넣어 강제로 실패를 일으키게 해볼 것.