콘텐츠로 이동

11-27-클린코드

클린코드 p408-p446


웹소켓 예제

  • I/O - 소켓 사용, 데이터베이스 연결, 가상 메모리 스와핑 기다리기 등
  • 프로세서 - 수치 계산, 정규 표현식 처리, 가비지 컬렉션 등
  • 프로그램이 프로세서 연산에 시간이 걸린다면? 새로운 하드웨어를 추가하여 성능을 높인다.
    • CPU 사이클은 한계가 있기 때문에 스레드를 늘리는 건 해결책이 아님
  • I/O 연산에 시간에 시간을 보낸다면? 동시성이 성능을 높여줄 수 있음 -> 한쪽이 I/O를 기다리는 동안 다른 쪽이 CPU 활용
  • 스레드를 관리하는 코드는 스레드만 관리
    • 동시성 문제는 그 자체만으로도 추적하기 어렵다 -> 관리 전략이 변할 때 전체 코드에 미치는 영향이 작아지며 다른 책임을 간섭하지 않음
  • 다중 스레드 프로그램에서는 단일 책임 원칙이 중요

synchronized

public class IdGenerator {
    int lastIdUsed;

    public int incrementValue() {
        return ++lastIdUsed;
    }
}
- 반환값은 lastIdUsed 값과 동일하다. 두 값 모두 메서드를 호출하기 전보다 1이 크다.

2개의 스레드가 동시에 incrementValue()를 호출한다면?

public synchronized void incrementValue() {
    ++lastIdUsed;
}
- 어떤 스레드가 메서드를 실행하면 Intrinsic Lock 획득 -> 한번에 하나의 스레드만 - ++lastIdUsed 코드 구역이 임계구역 - 해당 작업이 완료되거나 예외가 발생하면 lock이 해제 - 대기하던 다른 스레드가 메서드 실행 - synchronized 키워드는 단계를 원자적 작업으로 묶어주어 다른 스레드가 끼어들지 못하게 강제

알아야 할 것

  • 공유 객체/값이 있는 곳
  • 동시 읽기/수정 문제를 일으킬 소지가 있는 코드
  • 동시성 문제를 방지하는 방법

다중 스레드 환경에서 안전하지 않은 클래스

  • SimpleDateFormat
  • 데이터베이스 연결
  • java.util 컨테이너 클래스
    • java.util.concurrent: 스레드에 안전한 집합 클래스 제공
  • 서블릿

메서드 사이에 존재하는 의존성

  • 서버 기반 잠금
    • 코드 중복이 줄어들고 성능이 좋아진다.
    • 오류 발생가능성 감소
    • 스레드 정책이 서버 하나로 구현
    • ADAPTER 패턴으로 API 변경 후 잠금 추가
    • 스레드에 안전하며 인터페이스가 확장된 집합 클래스 사용
  • 동기화 영역은 작을수록 좋다

데드락

  • 상호 배제 Mutual exclusion
    • 공유하는 자원을 여러 스레드가 동시에 사용하지 못하며 개수가 제한
    • 데이터베이스 연결, 쓰기용 파일 열기, 레코드 락, 세마포어 등
  • 잠금 & 대기 Lock & Wait
    • 스레드가 자원을 점유하면 작업을 마칠 때까지 필요한 나머지 자원까지 점유
  • 선점 불가 No preemption
    • 한 스레드가 다른 스레드로부터 자원을 빼앗지 못함
  • 순환 대기 Circular wait
    • 순환 구조로 서로서로 필요한 자원을 점유

데드락 피하기 전략

  • 상호 배제 조건 깨기
    • 동시에 사용해도 괜찮은 자원 사용
    • 스레드 수 이상으로 자원 수 사용
    • 자원을 점유하기 전 필요한 자원 확인
  • 잠금 & 대기 조건 깨기
    • 각 자원을 점유하기 전 확인하여 하나라도 점유하지 못하면 모든 자원을 내놓고 다시 시작
    • 기아 Starvation: 한 스레드가 계속해서 필요한 자원 점유를 못함
    • 라이브락 Livelock: 여러 스레드가 동시에 진입하면 모든 자원을 점유하지 못하고 다시 시작 반복
  • 선점 불가 조건
    • 다른 스레드로부터 자원을 뺏어오는 방법
  • 순환 대기 조건 깨기
    • 모든 스레드가 일정 순서에 동의하고 그 순서로만 자원을 할당
    • 자원 할당 순서와 사용 순서가 상이하여 자원을 필요 이상으로 점유
    • 순서에 따라 자원 할당하기가 어려움

다중 스레드 코드 테스트

public class ClassWithTreadingProblem {
    int nextId;

    public int takeNextId() {
        return nextId++;
    }
}
- nextId의 현재 값을 기억한다. - 스레드 두 개를 생성한다. 각 스레드가 takeNextId()를 한 번씩 호출한다. - nextId가 처음보다 2 증가했는지 확인한다. - nextId가 2 대신에 1만 증가할 때까지 위 단계를 반복한다.


에필로그

Test Obsessed!