일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 스파르타코딩클럽
- Switch Expressions
- 바운디드 타입
- Effective JAVA
- 브릿지 메소드
- 익명 클래스
- 람다식
- 로컬 클래스
- annotation processor
- 합병 정렬
- System.in
- Java
- 프리미티브 타입
- 정렬
- 자바스터디
- raw 타입
- 접근지시자
- System.err
- public 필드
- junit 5
- 항해99
- Study Halle
- github api
- 함수형 인터페이스
- 자바할래
- 상속
- auto.create.topics.enable
- 제네릭 타입
- System.out
- 제네릭 와일드 카드
- Today
- Total
코딩하는 털보
ArrayList와 동시성 본문
redis에서 서로 독립적으로 조회하는 작업을 여러 스레드로 병렬 처리하기 위해 parallelStream을 사용하였다.
// Get Projects
public List<ProjectResponseDto> getProjects(String rootId) {
RelationshipResponseDto[] relationships = service.getRelationships(rootId);
List<ProjectResponseDto> projectResponseDtoList = new ArrayList<>();
if (relationships != null) {
Arrays.stream(hasProject).toList().parallelStream().forEach(relationshipResponseDto -> {
Project project = service.getProject(project);
projectResponseDtoQueue.add(ProjectResponseDto.builder()
.id(project.getId())
.name(project.getName())
.build());
});
}
return projectResponseDtoList;
}
분명히 조회되어야 하는 데이터는 3개로 고정되어 있는데, response를 확인해보면 가끔 2개 또는 1개인 경우가 발생했다.
현상을 자세히 확인하기 위해 테스트 요청을 해보았다.
for i in {1..100}
do
curl --location 'http://localhost:8020/projects/1' 2>/dev/null | jq length >> test.log
done

100회 시도했을 때 10번 정도가 문제가 발생한다.
parallelStream()은 병렬 작업이지만 동기적으로 처리되기 때문에 모든 스레드가 작업을 완료할 때 까지 대기할텐데
원인은 병렬 처리에서 사용하는 ArrayList였다.
https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html
ArrayList (Java Platform SE 8 )
Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is
docs.oracle.com
Note that this implementation is not synchronized.
Java ArrayList는 동기화 되지 않는다라고 명시되어있다. 따라서 여러 스레드에서 동시에 ArrayList를 사용하면 문제가 발생할 수 있다.
ArrayList 대신 thread safe 구현체인 ConcurrentLinkedDeque를 사용하였다.
// Get Projects
public List<ProjectResponseDto> getProjects(String rootId) {
RelationshipResponseDto[] relationships = service.getRelationships(rootId);
Queue<ProjectResponseDto> projectResponseDtoQueue = new ConcurrentLinkedDeque<>();
if (relationships != null) {
Arrays.stream(hasProject).toList().parallelStream().forEach(relationshipResponseDto -> {
Project project = service.getProject(project);
projectResponseDtoQueue.add(ProjectResponseDto.builder()
.id(project.getId())
.name(project.getName())
.build());
});
}
return new ArrayList<>(projectResponseDtoQueue);
}