반응형
💋 동기화 문제 발생
class SynchronizationTest {
@Test
void testSynchronized() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
SynchronizedMethods summation = new SynchronizedMethods();
IntStream.range(0, 1000)
.forEach(count -> executorService.submit(summation::calculate));
executorService.awaitTermination(500, TimeUnit.MILLISECONDS);
assertThat(summation.getSum()).isEqualTo(1000);
}
private static final class SynchronizedMethods {
private int sum = 0;
public void calculate() {
setSum(getSum() + 1);
}
public int getSum() {
return sum;
}
public void setSum(int sum) {
this.sum = sum;
}
}
}
- 1000개의 쓰레드를 만들어, 각 쓰레드가 동일한 SynchronizedMethods 인스턴스의 sum 변수에 접근해 1씩 더하는 상황
- 예상대로라면 1000번 더하게 되므로, 결과가 1000이 나와야 하는데...!
- 이 테스트가 실패하는 이유는 SynchronizedMethods 클래스의 calculate() 메서드에서 여러 쓰레드가 동시에 접근하여 sum 변수를 수정하고 있는데, 이 때문에 동시에 수정하는 경우가 발생할 수 있기 때문
- 동시에 수정하면, 같은 값에 +1을 하는 경우가 발생할 수 있다.
- 여러 쓰레드가 동시에 calculate() 메서드에 접근하여 getSum() 메서드를 호출하고, 각각의 결과에 1을 더한 값을 setSum() 메서드를 통해 sum 변수에 저장하려고 할 때, 동시에 접근하는 경우에는 한 쓰레드의 계산 결과가 다른 쓰레드에 의해 덮어씌워질 수 있다.
- 따라서 동기화를 적용하여 한 번에 하나의 쓰레드만 접근하도록 해야 한다!!!
💋 동기화 문제 해결
✔ 메서드에 synchronized 키워드 추가
public synchronized void calculate() {
setSum(getSum() + 1);
}
이렇게 하면, 이 메서드는 이제 한 번에 한 쓰레드만 접근할 수 있다.
참고로, static 메서드에도 해당 키워드를 추가할 수는 있는데!
✔ 메서드 내부 블록에 synchronized 키워드 추가
public void calculate() {
synchronized (this) {
setSum(getSum() + 1);
}
}
메서드 전체에 한 번에 딱 1개의 쓰레드가 접근하도록 하는건 부담스러울 수도 있다.
이렇게 블록으로 일부만 synchronized되도록 만들 수 있다!
이건 나의 개인적으로 궁금했던 점
💋 참고자료
도움이 되었다면, 공감/댓글을 달아주면 깃짱에게 큰 힘이 됩니다!🌟
반응형
'JAVA' 카테고리의 다른 글
[JAVA] Reflection API: 개념, 사용법, 예시 코드 (0) | 2023.09.28 |
---|---|
[JAVA] Java Reflection API에서 클래스 이름 가져오기: getName() vs getCanonicalName() (0) | 2023.09.12 |
[JAVA] 쓰레드 풀(Thread Pool): 개념, 장점, 사용 방법, 코드 예시 (feat. Baeldung) (0) | 2023.09.09 |
[JAVA] 프로세스와 스레드: 개념, Java의 쓰레드 구현, I/O Blocking (0) | 2023.09.08 |
[JAVA] 좋은 객체 지향 설계의 5가지 원칙 (SOLID) (0) | 2023.05.01 |