10.Mutual Exclusion(상호 배제)
=>하나의 스레드가 사용 중인 공유 자원을 다른 스레드가 수정하면 안됨
1)공유 자원을 여러 개의 스레드가 동시에 사용했을 때 문제
=>공유 자원으로 사용할 데이터 클래스
실습
package java_1031.Multithread;
import java.util.concurrent.locks.ReentrantLock;
//자원을 가지고 연산을 하는 스레드에 사용할 클래스
public class ShareData implements Runnable{
//연산 결과를 지정할 속성
private int result;
//연산에 사용할 인덱스
private int idx;
//공유 코드 영역을 설정하기 위한 객체
static final ReentrantLock LOCK = new ReentrantLock();
//result의 getter 메서드
public int getResult() {
return result;
}
public void run(){
try {
for(int i=0;i<10;i++) {
//자물쇠를 채워서 unlock을 만날때 까지는 이 영역의 자원을 수정할 수 없음
LOCK.lock();
idx++;
Thread.sleep(10);
result =result+idx;
LOCK.unlock();
}
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
}
}
static final ReentrantLock LOCK = new ReentrantLock();을 생성하여
lock()메서드와 unlock()메서드 사용
main
package java_1031.Multithread;
public class MutexMain {
public static void main(String[] args) {
//Runnable 인터페이스로부터 상속받은 클래스
ShareData shareData = new ShareData();
//스레드 생성
Thread th1 = new Thread(shareData);
th1.start();
Thread th2 = new Thread(shareData);
th2.start();
try {
//30초 대기-앞의 작업이 스레드로 동작하기 때문에 작업이 끝날때까지 대기하고 결과를 출력
//바로찍으면 getResult가 먼저 실행될 수도 있음
Thread.sleep(3000);//스레드가 아니면 전부 다 돌고 getResult가 나옴.
//스레드가 2개면 첫번째 스레드가 돌 때 반복문에서 sleep을 만나면 다른 스레드로 감. 같은 변수를 사용하기 때문에 이상한 결과값이 나옴.
//해결방법은 간단함. synchronized로 묶어주기만 하면 됨. 단, 다른게 못쓰도록 하는 건 최소화시켜야 함
//또는 ReentrantLock클래스 이용. 이 방법이 권장됨
System.out.println(shareData.getResult());
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
}
}
210
synchronized 예
public void run(){
try {
for(int i=0;i<10;i++) {
synchronized(this) {
idx++;
Thread.sleep(10);
result =result+idx;
}
}
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
}
synchronized 없이 실행하면 이상한 결과값 출력.
=>ShareData 인스턴스를 1개만 만들어서 공유하는데 하나의 작업이 완료되기 전에 다른 스레드가 공유 자원을 수정하기 때문에 발생
해결 방법
=>한번에 실행되어야 하는 코드를 가진 영역을 찾고 메서드에 synchronized를 붙이던가 코드 영역을 synchronized(공유 객체){}로 묶어주면 됨.
이렇게 묶어주면 묶인 영역의 코드를 동시에 수정할 수 없음
되도록이면 synchronized 메서드를 만드는 것 보다 블럭을 만드는 것을 권장
메서드를 묶게 되면 영역이 커져서 공유도가 떨어지기 때문
최근에는 위의 방법 말고 main에서 사용한 ReentrantLock이라는 클래스를 이용하는 것을 권장
=>인스턴스를 생성하고 lock이라는 메서드로 공유 영역을 만들고 unlock이라는 메서드로 공유 영역을 해제
'JAVA' 카테고리의 다른 글
221031 Semaphore (0) | 2022.10.31 |
---|---|
221031 생산자와 소비자 문제 (0) | 2022.10.31 |
221031 Thread2. Multi Thread (0) | 2022.10.31 |
221028 Daemon Thread (0) | 2022.10.28 |
221028 Thread (0) | 2022.10.28 |