반응형
동기화 메소드와 동기화 블록
공유 객체를 사용할 때 주의할 점
멀티 스레드 프로그램에서는 스레드들이 객체를 공유해서 작업해야 하는 경우가 있다.
이 경우, 스레드 A를 사용하던 객체가 스레드 B에 의해 상태가 변경될 수 있기 때문에 스레드 A가 의도했던 것과는 다른 결과를 산출할 수도 있다.
public class User1 extends Thread{
private Calculator calculator;
@Override
public void run() {
calculator.setmemory(100);
}
public void setCalculator(Calculator calculator) {
this.setName("User1");
this.calculator = calculator;
}
}
public class User2 extends Thread{
private Calculator calculator;
@Override
public void run() {
calculator.setmemory(50);
}
public void setCalculator(Calculator calculator) {
this.setName("User2");
this.calculator = calculator;
}
}
public class Calculator {
private int memory;
public int getMemory(){
return memory;
}
public void setmemory(int memory){
this.memory = memory;
try{
Thread.sleep(2000);
}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName() + ": " + this.memory);
}
}
public class MainThreadExample {
public static void main(String[] args){
Calculator calculator = new Calculator();
User1 user1 = new User1();
user1.setCalculator(calculator); // 공유 객체 설정
user1.start();
User2 user2 = new User2();
user2.setCalculator(calculator);
user2.start();
}
}
User1, User2 스레드가 Calculator라는 공유객체를 사용한다. User1 스레드가 먼저 Calculator memory 필드에 100을 저장하고 2초간 일시정지 상태에서, User2 스레드가 memory 필드값을 50으로 변경한다.
2초가 지나 User1 스레드가 다시 실행상태가 되서 memory 필드 값을 출력하면 User2가 저장한 50이 나오게 된다.
동기화 메소드 및 동기화 블록
위와 같은 상황을 피하기 위해서는, 스레드가 사용 중인 객체를 다른 스레드가 변경할 수 없도록 잠금을 걸어야 한다. 멀티 스레드 프로그램에서 단 하나의 스레드만 실행할 수 있는 코드 영역을 임계 영역(critical section)이라고 한다.
자바는 임계 영역을 지정하기 위해 동기화(synchronized) 메소드와 동기화 블록을 제공한다.
public synchronized void method(){
임계 영역; // (하나의 스레드만 실행)
}
// 메소드안에서 일부 내용만 임계 영역으로 만들고 싶다면 동기화(synchronized) 블록을 만든다.
public void method(){
// 여러 스레드 실행 가능 영역
synchronized(공유객체){ // 공유객체가 자기자신이면 this 삽입
임계 영역;
}
// 여러 스레드 실행 가능 영역
}
위의 문제점을 수정해 보자.
public class Calculator {
private int memory;
public int getMemory(){
return memory;
}
public synchronized void setmemory(int memory){
this.memory = memory;
try{
Thread.sleep(2000);
}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName() + ": " + this.memory);
}
}
memory를 설정하는 부분에 synchronized 를 추가하여 다른 스레드가 실행할 수 없게 하였다. (동기화 메소드)
public class Calculator {
private int memory;
public int getMemory(){
return memory;
}
public void setmemory(int memory){
// 동기화 블록 생성
synchronized (this) {
this.memory = memory;
try{
Thread.sleep(2000);
}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName() + ": " + this.memory);
}
}
}
이렇게 동기화 블록을 이용할 수도 있다.
반응형
'프로그래밍 노트 > JAVA' 카테고리의 다른 글
[JAVA] 다른 스레드에게 실행 양보(yield()) (0) | 2019.03.02 |
---|---|
[JAVA] 스레드 상태(Thread_3) (0) | 2019.03.02 |
[JAVA] 스레드 생성 및 동작방식(Thread_1) (0) | 2019.02.25 |
[JAVA] 제네릭(Generic) 문법 정리 (4) | 2019.02.12 |
[JAVA] final 필드와 상수, final 클래스와 final 메소드 (0) | 2018.11.26 |