[TIL/JAVA] AtomicInteger
Arrays.stream()을 사용하며 내부에서 index값이 필요해 다른 반복문에서 사용하는 것처럼 아래의 코드로 처리 할려고 했는데 IDE에서 final 또는 atomic으로 사용하라는 에러 문구가 발생했다.
int index = 0;
Arrays.stream(arr).forEach((num) => {
...
index++;
}

람다 표현식 내부에 사용되는 변수가 왜 final 형이어야 하는지 부터 찾아보자.
Lambda
람다 식이란?
method와 비슷하지만 이름과 파라메터의 타입을 지정할 필요없이 사용 가능하다.
(파라메터1, 파라메터2, ...) -> { // 하나의 명령문만 있을경우 중괄호를 생략할 수 있다. }
위와 같이 간결하게 사용이 가능하며 단 한 번만 사용된다.
지역변수와 람다
람다의 경우 참조하는 지역변수는 final 이거나 유사 final 이어야하므로 수정이 불가능하다.
이 이유는 멀티 스레드 환경에서의 안정성과 일관성을 위해 람다 내부에서 지역변수가 '캡처링' 되어 사용되기 때문이다.
'캡처링'된다는 뜻은 해당 변수의 값이 복사되어 사용된다는 것이다.
일반적으로 사용되는 지역 변수의 경우 stack 에 저장되서 사용되지만 람다의 경우 heap 영역에 저장 된다.
- 람다가 실행될 때 변수가 존재하지 않을 경우 문제가 되기 때문에 이런 형태가 되었다고 한다.
그렇다면 Atomic을 사용하는 이유는?
AtomicInteger의 경우 int 자료형을 가지고 있는 wrapping 클래스로 멀티 스레드 환경에서 동시성을 보장한다.
Atomic의 경우 CAS(Compare And Swap)를 이용 한다.
CAS (Compare And Swap) Algorithm?
메모리 위치의 내용을 주어진 값과 비교하고 동일한 경우에만 해당 메모리 위치의 내용을 새로운 값으로 수정하는 것
즉, 비교하여 바꾸어주는 것을 뜻한다.
따라서, 람다 내부에서는 일관성 보장이 되어야 하는데 이를 만족시켜 주는것이 Atomic이다.
AtomicInteger
드디어 본론으로 돌아와서 AtomicInteger를 사용하는 방법은
1. AtomicInteger객체를 선언한다.
AtomicInteger atomicNum = new AtomicInteger();
위와같이 선언하면 초기값은 0으로 세팅되며 변경을 위해서는 인자로 정수를 넣어주면 된다.
2. 사용 방법
값의 변경을 위해서는 .set(int), 읽어오기 위해서는 .get(), 읽어온 후 값을 변경하기 위해서는 .getAndSet(int)를 사용하면 된다.
atomicNum.set(10); //10으로 변환
System.out.printlv(atomicNum.getAndSet(20)) // 10을 출력 후 20으로 값을 변환
System.out.printlv(atomicNum.get()) // 20을 출력
그리고 atomic의 .getAndIncrement(), .incrementAndGet(), .getAndDecrement(), .decrementAndGet() 등을 사용하면 1씩 증가 감소를 편하게 사용할 수 있다.
AtomicInteger atomicNum = new AtomicInteger();
System.out.printlv(atomicNum.getAndIncrement()) // atomicNum++;
System.out.printlv(atomicNum.incrementAndGet()) // ++atomicNum;
System.out.printlv(atomicNum.getAndDecrement()) // atomicNum--;
System.out.printlv(atomicNum.decrementAndGet()) // --atomicNum;
결론
따라서 내부에서 사용하기 위해 밑과 같이 작성하여 사용했다.
AtomicInteger atomicNum = new AtomicInteger();
Arrays.stream(arr).forEach((num) => {
...
atomicNum.set(atomicNum.incrementAndGet());
}
나는 Lamda내부에 index체크를 위해 atomic을 사용해봤는데 다른 방식이 있는지 다음에 찾아봐야 겠다.