자바를 공부하면서 멀티스레드에 대해 간단한 실습을 해 보았는데 내 생각과 다른 결과물이 나와 이에 대해 공부해 보려한다.
스태틱 영역 | ||
스택 영역 | 힙영역 | |
스레드 | 스레드 |
멀티스레드는 하나의 T메모리 안에서 스택 영역만 분할한 것이기 때문에 하나의 스레드에서 다른 스레드의 스택 영역에는 접근 할 수 없지만 스태틱 영역과 힙 영역은 공유해서 사용하는 구조다. 출처-스프링 입문을 위한 자바 객체 지향의 원리와 이해
위의 메모리 구조를 이해 하였다면 아래의 코드를 살펴보자
public class Main extends Thread{
static int share;
public static void main(String[] args) {
Main t1 = new Main();
Main t2 = new Main();
t1.start();
t2.start();
}
public void run(){
for(int count = 0; count < 10; count++){
System.out.println(share++);
try {
sleep(10000);
}catch (InterruptedException e){
}
}
}
}
위코드를 보면 share 변수에 static키워드가 붙어있다. 그럼 share변수가 클래스의 멤버로 스태틱영역에 배치 될 것이다.
멀티스레드는 스태틱 영역과 힙 영역은 서로 공유해서 사용한다고 알고 있다. 그렇기에 t1 과 t2 두개의 스레드는 같은 share를 공유하기에 나는 최종 출력 결과물은 당연히 19가 출력이 되어야 한다고 생각했다. 그러나 내 예상을 뒤엎고 결과물은 17이 나왔다.
위의 결과물이 나온 이유는 쓰레드의 경쟁조건(race condition) 때문이었다. t1 쓰레드가 작업하던 도중에 t2 쓰레드에게 제어권이 넘어갔을때 쓰레드 t1이 작업하던 공유데이터를 쓰레드 t2가 임의로 변경하였다면 다시 쓰레드 t1이 제어권을 받아서 나머지 작업을 마쳤을 때 원래 의도했던 것과는 다른 결과물이 나온것이다. 위의 이미지를 보면 8과 11이 중복해서 나온것을 확인할 수 있다.
이러한 일이 발생하는 것을 방지하기 위해서 한 쓰레드가 특정 작업을 끝마치기 전까지 다른 쓰레드에 의해 방해받지 않도록 하는 것이 필요하다. 그래서 도입된 개념이 바로 임계 영역(critical section)과 잠금(lock)이다.
이를 방지하기 위해서는 t1 쓰레드가 share변수를 조작하고 있을때 t2쓰레드가 share변수에 간섭하지 못하게 해야한다. 이처럼 한 쓰레드가 진행 중인 작업을 다른 쓰레드가 간섭하지 못하도록 막는 것을 쓰레드의 동기화(synschronized) 라고 한다.
public class Main extends Thread{
static int share;
public static void main(String[] args) {
Main t1 = new Main();
Main t2 = new Main();
t1.start();
t2.start();
}
public void run(){
for(int count = 0; count < 10; count++){
synchronized (Main.class) {
System.out.println(share++);
}
try {
sleep(10000);
}catch (InterruptedException e){
}
}
}
}
위의 코드를 보면 run 메서드 내의 일부 코드를 블럭{}으로 감싸고 블럭 앞에 synchronized를 붙여 임계영역을 할당했다. 이 영역 안으로 들어가면서 부터 쓰레드는 지정된 객체의 lock을 얻게 되고 이 블럭을 벗어나면 lock을 반납하게 된다. 모든 객체는 lock을 하나씩 가지고 있으며 해당 객체의 lock을 가지고 있는 쓰레드만 임계 영역의 코드를 수행할 수 있다. 그리고 다른 쓰레드들은 lock을 얻을 때까지 기다리게 된다.
결과물을 다시 확인해 보니
내가 원하는 답을 얻을 수 있었다.
*생각해 볼것
- 데이터 베이스의 트랜잭션과 비슷한 느낌을 받았다. 나중에 실무에서 직접 코드를 짤때 어떤식으로 연관이 있을지 공부해 봐야겠다.
- 이렇게 임의 적으로 lock을 걸어준다면 싱글스레드와 다를게 없을것 같았다. 어떤상황에서 어떤식으로 사용하면 좋은지 한번 생각해 보자
참고서적 - java의 정석, 스프링 입문을 위한 자바 객체 지향의 원리와 이해
'자바' 카테고리의 다른 글
java11과 17의 차이 (0) | 2024.09.03 |
---|---|
객체지향 설계 5원칙 (0) | 2024.07.06 |
메모리와 StackOverFlow (0) | 2024.06.28 |
자바의 메모리 구조 (0) | 2024.06.28 |