Friday, July 13, 2007

MultiThread


Multi Thread
스레드란 ‘메서드가 동시에 실행되는것‘인데 이건 동시에 메서드작업이 진행된다는 의미이다. 여러개의 스레드가 동시에 작업이 진행될때 문제가 되는것이 바로 공유자원의 문제이다.
사용할수있는 자원은 한 개인데 그것을 여러개의 스레드가 동시에 이용하려고 할때 공유자원에 문제가 생긴다.
즉, 화장실은 한 개인데 것도 공용화장실이 한 개인데 기다리는사람이 3명일 경우 한명이 들어가면 나올때 까지 기다려야하는데 기다리지 않고 들어가면 문제가 발생하는것이다.
결국 기다리게 만드는 것이 해결책이라 할수 있겠다.
화장실에 들어가서 문을 잠그면 되는데 그것이 메모리에 락(Lock)을 거는 방법인데,한개의 스레드가 공유자원을 다 쓸때 까지 다른스레드들을 대기시키는 것이다.
이렇게 순서대로 사용하게하는기법을 동기화(Synchronization)라고 한다.
즉 줄서기인것이다

import java.io.*;
import java.util.*;

class Test{ //공유할자원을 한개 생성할 클래스
private int memory=100; //공유자원인 메모리

public int getMemory(){ //값을계산해서 변경할 메소드생성
return this.memory;
}
public void setMemory(int memory){ //계산된공유자원 저장할 메소드
this.memory=memory;
}
public void addMemory(int add){ //메모리에 값 더할 메소드
int m = this.getMemory(); //설정되어 있는값을 읽어들임 **중요부분**
try{
Thread.sleep(3000); //3초후에 동작
}catch(Exception e){
e.printStackTrace();
}
this.setMemory(m+add); //3초후에 메모리설정값에 add값을 더해서 변경
}
public void minusMemory(int min){ //메모리에 값을 뺄 메소드
int n = this.memory;
try{
Thread.sleep(200); //0.2초 후에 동작
}catch(Exception e){
e.printStackTrace();
}
this.setMemory(n-min); //0.2초 후에 메모리 설정값에 min값을 빼서 변경
}
}
class Donhak extends Thread{ //값을 더할스레드 생성
public void run(){
MultiThread.Test2.addMemory(50); //공유메모리의 50값을 더함
System.out.println("거기에50더하기 "+ MultiThread.Test2.getMemory()); //더해진 값을 출력
}
}
class Mina extends Thread{ //값을 빼는 스레드 생성
public void run(){
MultiThread.Test2.minusMemory(50); //공유메모리의 50값을 뺌
System.out.println("50빼기 "+ MultiThread.Test2.getMemory()); //빼진 값을 출력
}
}
public class MultiThread {
public static Test Test2 = new Test(); //Test와 같은 객체 Test2생성

public static void main(String[] args)throws Exception{ //메인 메소드
Donhak d = new Donhak(); //start를 할 객체 생성
Mina m = new Mina(); //start를 할 객체 생성
d.start(); //Donhak쓰레드 동작
try{
Thread.sleep(200);
}catch(Exception e){
e.printStackTrace();
}
m.start(); //Mina 스레드 동작
}
}

////////////////////////출력물///////////////////////////////
50빼기 50
거기에50더하기 150


이렇게 하면 Donhak이 **중요부분** 에서 100의 값을 읽어온후 3초간 기다린다.
그사이에 0.2초후에 Mina가 동작하는데 0.2초후에 100의 값을 읽어서 50을 뺀다.
그리고 설정값을 100에서 50으로 바꿔주는데, Donhak은 바뀐 50값에서 50을 더하는게
아니라 그전에 읽어들인 100의 값에서 50을 더하기 때문에 150의 값을 출력하게 된다
결국 공유자원에서의 순서의 문제로 오류가 발생한다. 은행에서 이럴경우 큰일난다.

####해결책#####
public synchronized void addMemory(int add){ //synchronized 메서드로 생성해서
//이메소드 안에서 생성되는 모든변수에 Lock가 걸리게 한다
int m = this.getMemory();
try{
Thread.sleep(3000);
}catch(Exception e){
e.printStackTrace();
}
this.setMemory(m+add);
}
public void minusMemory(int min){
synchronized(this){ //{}안에 현재 클래스에 사용된 맴버변수에 대한 동기화가 보장된다
int n = this.memory;
try{
Thread.sleep(200);
}catch(Exception e){
e.printStackTrace();
}
this.setMemory(n-min);
}
}

이렇게 synchronized 메소드를 사용해 addMemory에서 공유자원을 묶어줘야
Donhak이 작업을 할 3초를 기다린후에 Mina가 작업을해서 100에서 50을 더한수에
50을 빼게 된다.
//////////결과물////////
거기에50더하기 150
50빼기 100
}

No comments: