이정우
1. 📌 핵심 개념 정리
✅ 요약하기
각자 해당 챕터에서 중요하다고 느낀 개념이나 아이디어를 간략하게 정리하고 개선 전, 후에 대한 예시 코드를 비교하며 개념을 설명합니다.
- 동시성이 필요한 이유
-
동시성이란?
- 동시성은
결합(coupling)
을없애줄이는 전략이다. - 프로그램에서
무엇(what)
언제(when)
을를 분리하는전략
- 동시성은
스레드가 하나인 프로그램은무엇과언제가 서로 밀접하기에 호출 스택역할을살펴보면 프로그램 상태가 바로 드러난한다.- 단일 스레드 프로그램
을 디버깅하는 프로그래머는은정지점(breakpoint)무엇과 언제가 강하게 결합을되어정한 후있어느 정지점에 걸렸는지를 확인하여 시스템상태를파악한관리가 어렵다. - 반면, 동시성을 도입하면 프로그램이 독립적인 작업 단위로 나뉘어
구조적 설계 및 효율성
이 향상된다.
성능 및 응답성 향상
정보 수집기(information aggregator)
같은 프로그램은 여러 웹사이트에서 정보를 가져오는데, 단일 스레드보다 동시성을 활용하면 성능이 크게 향상된다.- 사용자 요청이 증가할수록 동시성을 통해 시스템이 효율적으로 응답할 수 있다.
- ex) 다수의 사용자 요청을 한 번에 처리하는 웹 애플리케이션
작업 프로그램은분배 거대한및 루프병렬 하나가 아닌 여러개의 작은 협력 프로그램으로 보인다.처리
따라서동시성을 활용하면 시스템을 여러 작은 단위로 나눠 병렬로 처리할 수 있다.- 예) 빅데이
해하기가터쉽고분석문제시스템에서는 대량의 정보를분병렬로 처리하면 처리 속도를 크게 향상시킬 수 있다.
미신과 오해
- 동시성이 항상 성능을 높여주지는 않는다.
- 긴 대기 시간을 공유하는 경우 성능 향상이 가능하지만, 독립적인 계산을 수행하는 경우에는 성능 향상이 크지 않을 수도
쉽있다.
- 긴 대기 시간을 공유하는 경우 성능 향상이 가능하지만, 독립적인 계산을 수행하는 경우에는 성능 향상이 크지 않을 수도
- 동시성을 구현해도 설계는 변하지 않는다.
- 단일 스레드 시스템과 다중 스레드 시스템은 설계 방식이 다르므로 이를 고려해야 한다.
- 웹 애플리케이션에서 항상 필요한 것은 아니다.
- 웹 서버는 본래 각 요청을 독립적인 스레드에서 처리하므로, 필요하지 않은 경우도 있다.
- 동시성의 난관
- 다수의 부하를 유발한다.
- 성능이 저하될 수 있으며, 코드가 복잡해진다.
- 설계가 복잡해진다.
- 단순한 문제라도 동시성을 고려하면 복잡성이 증가한다.
- 테스트가 어렵다.
- 동시성 버그는 재현하기 어려우며, 특정 경로에서만 발생하는 문제를 찾기 어렵다.
- 근본적인 설계 전략이 필요하다.
- 동시성은 단순히 추가하는 것이 아니라, 설계 단계부터 고려해야 한다.
public class X {
private int lastIdUsed;
public int getNextId() {
return ++lastIdUsed;
}
}
- 위 코드에서
lastIdUsed
를 공유하는 두 개의 스레드가getNextId()
를 호출하면, 예상치 못한 결과가 발생할 수 있다. - 두 스레드가 동시에 실행되면
경합 조건(race condition)
이 발생하여, 예상과 다른 값이 반환될 가능성이 높다. - 자바 메모리 모델과 JIT 최적화 등을 이해하지 않으면 문제 해결이 어려울 수 있다.
- 동시성 방어 원칙
- 동시성 코드가 일으키는 문제로부터 시스템을 방어하는 원칙과 기술
- 단일 책임 원칙(SRP)
- 메서드/클래스/컴포넌트를 변경할 이유가 단 하나여야 한다는 원칙
- 동시성은 복잡성 하나만으로도 따로 분리할 이유가 충분 -> 동시성 관련 코드는 다른 코드와 분리해야 한다.
- 동시성 구현 시 고려사항
- 동시성 코드는 독자적 개발,변경,조율 주기가 있다.
- 동시성 코드는 독자적 난관이 있다.
- 잘못된 동시성 코드의 실패원인은 다양하다.
[권장사항] 동시성 코드는 다른 코드와 분리하라.
- 따름 정리 (corollary) : 자료 범위를 제한하라
- 객체 하나를 공유한 후 동일 필드르 ㄹ수정하던 두 스레드간의 간섭으로 오류발생
- 이에 관한 해겨랙으로 공유객체를 사용하는 코드 내
임계영역(critical section)
을synchronized
키워드로 보호 하는 것을 권장한다. - 공유 자료 수정 위치가 많을 수록 다음 가능성도 증가한다.
- 보호할 임계영역을 빼먹는다. 이로인해 공유 자료를 수정하는 모든 코드가 망가진다.
- 모든 ㅇ미계영역을 올바로 보호했는지 확인하느라 같은 고생을 반복한다.
- 버그 찾기가 더욱 힘들어진다.
[권장사항] 자료를 캡슐화(encapsulation)하라. 공유 자료를 최대한 줄여라
- 따름 정리 : 자료 사본을 활용하라
- 공유 자료를 줄이려면 처음부터 공유하지 않는 방법이 제일 좋다.
- 공유 객체를 피하는 방법이 있다면 코드가 문제를 일으킬 가능성이 대폭 감소한다.
- 따름 정리 : 스레드는 가능한 독립적으로 구현하라
- 다른 스레드와 자료를 공유하지 않는 독자적 스레드를 구현한다.
- 각 스레드는 클라이언트 요청 하나를 처리한다.
- 모든 정보는 비공유 출처에서 가져오며 로컬 변수에 저장한다.
- 각 스레드는 다른 스레드와 동기화할 필요가 없어 독자적으로 돌아갈 수 있다.
[권장사항] 독자적인 스레드로, 가능하면 다른 프로세서에서, 돌려도 괜찮도록 독립적인 단위로 자료를 분할하라
- 단일 책임 원칙(SRP)
- 라이브러리를 이해하라
- 자바 5로 스레드 코드 구현 시 고려사항
- 스레드 환경에 안전한 컬렉션을 사용한다. (자바 5이상 제공)
- 서로 무관한 작업을 수행할 때는 executor 프레임워크를 사용한다.
- 가능하다면 스레드가 차단(blocking)`않는 방법을 사용한다.
- 일부 클래스 라이브러리는 스레드에 안전하지 못하다.
- 스레드 환경에 안전한 컬렉션
- java.util.concurrent
- 다중 스레드 환경에서 사용해도 안전하고 성능이 좋다.
- ConcurrentHashMap은 실제로 대부분의 상황에서 HashMap보다 빠르다.
- 동시 읽기/쓰기 지원
- 자주 사용하는 복합 연산을 다중 스레드 상에서 안전하게 만든 메서드로 제공한다.
- ReentrantLock : 한 메서드에서 잠그고 다른 메서드에서 푸는 락(lock) 이다.
- Semaphore : 전형적인 세마포다. 개수(count)가 있는 락이다.
- CountDownLatch : 지정한 수만큼 이벤트가 발생하고 나서야 대기 중인 스레드를 모드 해제하는 락이다. 모든 스레드에게 동시에 공평하게 시작할 기회를 준다.
[권장사항] 언어가 제공하는 클래스를 검토하라. - java.util.concur-rent - java.util.concurrent.atomic - java.util.concurrent.locks
- java.util.concurrent
- 한 줄 요약 내용
- 개선 전
개선 전 코드
개선 전 코드의 문제점을 작성합니다.
- 개선 후
개선 후 코드
개선 후의 코드에 대한 설명을 작성합니다.
-
한 줄 요약 내용
2. 🤔 이해가 어려운 부분
🔍 질문하기
책을 읽으며 이해하기 어려웠던 개념이나 명확하지 않았던 내용을 정리합니다.
- 개념 또는 원칙의 이름
- 어려웠던 부분
해당 개념이 헷갈리거나 명확하지 않았던 점을 구체적으로 설명합니다. - 궁금한 점
해당 개념이 어떤 원리로 동작하는지, 실무에서 어떻게 활용되는지 등을 질문 형태로 정리합니다.
- 어려웠던 부분
- 개념 또는 원칙의 이름
- 어려웠던 부분
. - 궁금한 점
.
- 어려웠던 부분
- 개념 또는 원칙의 이름
- 어려웠던 부분
. - 궁금한 점
.
- 어려웠던 부분
3. 📚 참고 사항
📢 논의하기
관련된 자료가 있다면 공유하고, 더 깊이 논의하고 싶은 아이디어나 의견을 정리합니다.
- 관련 자료 공유
- 추가 자료
관련 블로그 글이나 공식 문서 링크를 제공합니다.
- 추가 자료
- 논의하고 싶은 주제
- 주제
논의하고 싶은 내용을 간략히 정리합니다. - 설명
논의하고 싶은 이유를 작성합니다.
- 주제