프로그래밍 정리/자바

공유자원의 접근

주누다 2013. 6. 17. 15:26
반응형

- 여러 개의 쓰레드가 생성되었을 때 하나의 자원을 이용하는 상황은 자주 발생. 공유자원을 이용할 때 문제가 발생하게 되는

근본적인 이유는 동시에 작업을 진행하는 쓰레드의 특성 때문.


- 공유자원이 문제가 되는 이유

-> 동시에 작업을 진행하는 쓰레드의 특성 때문


- Bank라는 클래스의 객체를 NotSynMain에서 스태틱으로 생성함으로써 myBank객체는 프로그램의 하나의 메모리만 생성.

-> Bank 클래스

class Bank{

// ...

}

-> NotSynMain 클래스의 static 멤버

class NotSynMain{

public static Bank myBank = new Bank();

// ... 작업

}

- 그리고 다음과 같이 두 개의 쓰레드에서 NotSynMain의 myBank객체를 이용한다면 myBank는 공유자원이 됨.

-> Park 쓰레드 클래스

class Park extends Thread{

public void run(){

// NotSynMain.myBank 사용

}

}


-> ParkWife 쓰레드 클래스

class ParkWife extends Thread{

public void run(){

// NotSynMain.myBank 사용

}

}

-> 두 개의 쓰레드가 같이 동시에 실행된다면 공유자원의 문제가 발생.


==========================================================================================================



public class Bank {


private int money = 10000; // 예금 잔액

public int getMoney(){

return this.money;

}

public void setMoney(int money){

this.money = money;

}

public void saveMoney(int save){

int m = this.getMoney();

try{

Thread.sleep(3000);

}catch (Exception e) {

// TODO: handle exception

}

this.setMoney(m + save);

}

public void minusMoeny(int minus){

int m = this.money;

try{

Thread.sleep(2000);

}catch (Exception e) {

// TODO: handle exception

}

this.setMoney(m - minus);

}

}




public class Park extends Thread{

@Override

public void run() {

// TODO Auto-generated method stub

NotSyncMain.myBank.saveMoney(3000);

System.out.println("minusMoney(3000) : " + NotSyncMain.myBank.getMoney());

}

}



public class ParkWife extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
NotSyncMain.myBank.minusMoeny(1000);
System.out.println("minusMoney(1000) : " + NotSyncMain.myBank.getMoney());
}
}


public class NotSyncMain {

public static Bank myBank = new Bank();
public static void main(String[] args) {
Park p = new Park();
ParkWife w = new ParkWife();
p.start();
try{
Thread.sleep(200);
}catch (Exception e) {
// TODO: handle exception
}
w.start();
}
}
============================================================================================================

- 공유자원 Bank myBank의 이용
-> NotSyncMain.myBank.saveMoney(3000);    // 3000원 입금
-> NotSyncMain.myBank.minusMoney(1000);    // 1000원 출금

- Bank myBank객체는 통장과 같은 역할을 하며, myBank는 기본적으로 10000원이 예금된 상태. 그리고 Park의 쓰레드에서 3000원을 입금하려고 하며, ParkWife 쓰레드에서 1000원을 출금하려 함. 이 때 입금을 위해서는 3초의 시간이 걸리며, 출금을 위해서는 0.2초의 시간이 소요. 일반적인 계산으로는 다음과 같이 계산되어야 함.
-> 동기화가 보장된 상태에서의 입출금 금액
=> 12000(결과금액) = 10000(원금) + 3000(입금) - 1000(출금)
-> 하지만 위의 예제의 실행결과는 13000원이 출력됨. 그 이유는 Park의 run()에서 예금된 금액을 가져온 후 3초의 시간이 지연된 후 입금이 처리되기 때문.

-> public void saveMoney(int save){
int m = this.getMoney();        // 예금되어 있는 금액 확인
try{
Thread.sleep(3000);   
}catch(InterruptedException e){e.printStackTrace();}
this.setMoney(m + save);    // 입금처리

- 3초의 시간이 지연되는 동안 다른 곳에서 작업이 이루어진다면 문제가 발생할 것. 즉, 출금할 때 minusMoney()에서 0.2초의 시간으로 출금작업이 중간에 처리되어 버리기 때문에 계산은 다음의 절차대로 됨.
-> 동기화가 유지되지 않은 경우 입출금의 계산 절차
=> Park이 10000을 읽어감
=> Park는 3초 대기
=> Park이 대기하는 동안 ParkWife 또한 10000을 읽어감
=> Park이 대기하는 동안 ParkWife 0.2초 대기
=> Park이 대기하는 동안 ParkWife는 1000원을 출금
=> Park이 대기하는 동안 ParkWife는 작업완료(남은 돈은 9000원)
=> Park은 3초 대기한 후 읽어온 10000으로 3000원 입금
=> 결과는 13000원
-> 동기화의 유지
=> Park이 Bank myBank를 사용할 때 ParkWife는 Bank myBank를 사용하기 위해서 대기해야 함.

- 즉 Park p가 Bank myBank를 사용하고 있을 때 다른 곳에서 myBank를 사용하려 한다면 다른 쓰레드는 대기하도록 만들어야함.
위의 예에서 실제 공유자원은 Bank의 money임. 즉 Bank myBank의 멤버 변수인 money의 메모리를 락(Lock)으로 봉쇄한다면 다른 쓰레드는 이를 이용하지 못할 것. 공유자원에 락(Lock)을 걸기 위해서 synchronized 키워드를 이용하면 됨.


반응형

'프로그래밍 정리 > 자바' 카테고리의 다른 글

synchronized의 활용  (0) 2013.06.17
synchronized  (0) 2013.06.17
멀티쓰레드와 문제점  (0) 2013.06.17
쓰레드 죽이기  (0) 2013.06.17
NotRunnable 상태 만들기  (0) 2013.06.17