본문 바로가기

Java

멀티 스레드의 스레드들이 객체를 공유하는데 임계영역의 문제를 해결하지 않은 경우

  • '이것이 자바다'의 12장의 예제를 참고하여 실습한 내용입니다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SynchronizedCalculator {
 
    private int memory;
 
    public int setMemory(int memory) {
        this.memory = memory;
 
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
 
        }
        System.out.println(Thread.currentThread().getName() + " = " + this.memory);
        return this.memory;
    }
}
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SynchronizedUser1 extends Thread {
    private SynchronizedCalculator synchronizedCalculator;
    private int memory = 0;
 
    public int getMemory() {
        return memory;
    }
 
    public void setMemory(int memory) {
        this.memory = memory;
    }
 
    public void setSynchronizedCalculator(SynchronizedCalculator synchronizedCalculator) {
        this.setName("User1");
        this.synchronizedCalculator = synchronizedCalculator;
    }
 
    @Override
    public void run() {
        memory = synchronizedCalculator.setMemory(memory);
    }
}
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SynchronizedUser2 extends Thread {
    private SynchronizedCalculator synchronizedCalculator;
    private int memory = 0;
 
    public int getMemory() {
        return memory;
    }
 
    public void setMemory(int memory) {
        this.memory = memory;
    }
 
    public void setSynchronizedCalculator(SynchronizedCalculator synchronizedCalculator) {
        this.setName("User2");
        this.synchronizedCalculator = synchronizedCalculator;
    }
 
    @Override
    public void run() {
        memory = synchronizedCalculator.setMemory(memory);
    }
}
cs

 

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
@Test
    @DisplayName("동기화 메소드로 공유 객체 사용")
    void multiThreadSynchronizedArea() {
        SynchronizedCalculator synchronizedCalculatorlc = new SynchronizedCalculator();
 
        SynchronizedUser1 user1 = new SynchronizedUser1();
        user1.setMemory(100);
        user1.setSynchronizedCalculator(synchronizedCalculatorlc);
        user1.start();
 
        SynchronizedUser2 user2 = new SynchronizedUser2();
        user2.setMemory(50);
        user2.setSynchronizedCalculator(synchronizedCalculatorlc);
        user2.start();
 
 
        try {
            Thread.sleep(3000);
        }catch (Exception e) {
 
        }
 
        assertAll(
                () -> assertThat(user1.getMemory()).isEqualTo(100),
                () -> assertThat(user2.getMemory()).isEqualTo(50)
        );
    }
cs

 

  • 중간에 Thread.sleep(3000);을 넣은 이유는 동기화 테스트를 위해 만든 클래스들이 임계영역에 동시에 접근하는 부분을 확인하기 전에 테스트 메서드가 종료되는 문제가 있어서 넣었습니다.

  • 우선 SynchronizedCalculator 클래스에서 콘솔에 출력해주는 것을 보면
  • SynchronizedUser1 클래스를 먼저 호출 했지만 User2 스레드부터 확인 할 수 있다
  • 이것은 컨택스트 스위칭에 의해 달라진다
  •  
  • 테스트 결과를 보면
  • SynchronizedUser1 클래스를 수행한 결과 100 이라는 값을 예상하고 있지만 실제 결과는 50 이기에 테스트를 실패했다
  • SynchronizedUser2 클래스는 수행한 결과값을 50 이라고 예상하고 있는데 실제 결과도 50 이 나왔기에 테스트를 통과해서 오류로 보이는 메시지가 없다
  • 이 테스트를 통해서 임계영역의 문제를 해결하지 않게 된다면 값의 일관성을 보장할 수 없다는 것을 알 수 있다