1. 개요
멀티스레드를 사용하여 꿈나무 한입 프로젝트를 개선하는 동안 발생한 문제이다. 다음은 공공데이터를 가져오는 코드의 일부이다.
공공데이터를 가져오기 위해 url을 만들고, 스레드에서 동작시키기 위해 람다식을 사용하였는데 위와 같은 에러를 잡아냈다. 람다 내부에서 사용되는 변수는 선언 후 수정되어서는 안된다는 뜻이다. IDE의 제안에 따라 다음과 같이 코드를 수정했다.
그러나 왜 이런 오류를 잡아냈는지 궁금했고, 이에 대해 찾던 중 람다 캡쳐링의 개념을 알게 되었다. 다음은 이에 대해 정리한 내용이다.
2. 람다 캡쳐링?
우선 람다 캡쳐링의 정의는 다음과 같다.
스택 영역에 있는 변수를 사용할 수 있도록 지역 변수의 복사본을 람다의 스택에 제공
이게 무슨 말인가? 위 코드를 생각해보자. 위 코드에서 람다를 실행시킬 때 다음과 같은 일이 일어난다.
만약 지역 변수가 있는 스레드가 종료되었는데, 람다에서 url을 사용하기 위해 이를 참조하려 하면 에러가 날 것이다. 이를 방지하기 위해 람다식이 실행될 때 원 메서드에 있는 변수가 람다에서 사용하는 스택 영역으로 복사된다.
그런데 만약 logic에 있는 url 변수가 변경된다고 하면 다음과 같은 일이 일어날 것이다.
로직에서는 url에 A로 변경되었는데, 람다식은 B라는 url을 가지고 연산을 수행한다. 스택끼리는 서로 정보를 공유하지 않으므로 원치 않는 값이 나오게 된다. 그렇기 때문에 람다식의 외부 변수는 사실상 final이어야 하는 제약조건이 생긴 것이다.
3. 인스턴스 필드
인스턴스 필드나 static 변수의 경우 위의 제약조건이 존재하지 않는다. 캡쳐링이 일어날 때 해당 변수의 참조 주소값을 가져오게 된다. Heap 영역에 변수가 존재하고, 각 스레드는 하나의 주소를 참조하여 Heap 영역에 있는 값을 바꾸게 되므로 위의 동시성 문제가 발생하지 않기 때문이다.
'Spring' 카테고리의 다른 글
[SpringBoot] Hello, Multimodule! - 멀티 모듈 설정 (2) | 2024.09.02 |
---|---|
Event 처리 (0) | 2024.07.05 |