쓰레드의 메모리 접근 방식과 그에 따른 문제점
class Counter {
int count = 0; // 공유되는 변수
public void increment() {
count++; // 첫 번째 쓰레드에 의해 실행
}
public void decrement() {
count--; // 또 다른 쓰레드에 의해 실행
}
public int getCount() { return count; }
}
class MutualAccess {
public static Counter cnt = new Counter();
public static void main(String[] args) throws InterruptedException {
Runnable task1 = () -> {
for(int i = 0; i < 1000; i++)
cnt.increment(); // 값을 1 증가
};
Runnable task2 = () -> {
for(int i = 0; i < 1000; i++)
cnt.decrement(); // 값을 1 감소
};
Thread t1 = new Thread(task1);
Thread t2 = new Thread(task2);
t1.start();
t2.start();
t1.join(); // t1이 참조하는 쓰레드의 종료를 기다림
t2.join(); // t2가 참조하는 쓰레드의 종료를 기다림
System.out.println(cnt.getCount());
}
}
일반적으로 1000번 증가 1000번 감소해서 0이 나와야 되는데 0이 나올 확률이 적음..
쓰레드1이 변수 num을 1 증가 시킨다고 하면 변수 num의 값을 가지고 와서 증가시키고 다시 갖다놓는 3단계를 거쳐야 한다.
쓰레드가 동시에 일어날때는 3단계 중간에 교체가 될 수 도 있어 갖다놓는 과정에서 다른 쓰레드가 계산한 값을 무시하고 갖다 놓을 수 있어 생각했던 값이 아닌 다른 값이 계산 될 수 있다.
특정 변수를 두 개 이상의 쓰레드가 동시 접근하면 이런 현상이 발생할 수 있다.
동기화(Synchronization) 메소드 - 특정 메소드를 둘 이상의 쓰레드가 접근하지 못하게 하는 것!
class Counter {
int count = 0;
synchronized public void increment() {
count++;
}
synchronized public void decrement() {
count--;
}
public int getCount() { return count; }
}
각각 다른 메소드라도 한 클래스 내에 있으면 동시에 둘 이상의 쓰레드가 접근하지 못하게 할 수 있다!!
단, 각각의 메소드가 기능이 엄청 많은데 단 한줄만 같은 변수를 접근하여 동기화를 해줘야 한다고 할때는 비효율 적이다!!
동기화(Synchronization) 블록
- 특정 메소드 중 특정 기능만이 둘 이상의 쓰레드가 접근하지 못하게 하는 것!
class Counter {
int count = 0;
public void increment() {
synchronized(this) { // 동기화 블록 - this라는 인스턴스를 대상으로 동기화 하겠다는 뜻.
count++;
}
}
public void decrement() {
synchronized(this) { // 동기화 블록
count--;
}
}
public int getCount() { return count; }
}
메소드 보다 더 작은 단위로 동기화 시킬 수 있다. 해당 메소드의 특정 기능만이 동시에 두 개 쓰레드가 접근하지 못하도록 하는 방법이다!
이 예제에서는 동기화 할 경우가 한 가지밖에 없어서 this를 사용했지만, 만약 변수가 2개 이상존재하고 각각의 변수에 대해 동기화 해야되는 블록이 존재한다면 this 대신 a1, a2 이런식으로 구분을 지어줄 수 있다.
'# 02 > Java' 카테고리의 다른 글
[Java] RxJava 세미나 (0) | 2019.12.20 |
---|---|
[윤성우 열혈자바] 34-3. 쓰레드를 생성하는 더 좋은 방법 (0) | 2019.10.28 |
[윤성우 열혈자바] 34-1. 쓰레드의 이해와 쓰레드의 생성 (0) | 2019.10.28 |
[윤성우 열혈자바] 33-3. NIO 기반의 입출력 (0) | 2019.10.28 |
[윤성우 열혈자바] 33-2. NIO.2 기반의 I/O 스트림 생성 (0) | 2019.10.28 |