다연이네

[days27] 동기화 본문

Java

[days27] 동기화

 다연  2020. 10. 27. 20:41
반응형

동기화

멀티스레드 프로세스의 경우 여러 스레드가 같은 프로세스의 자원을 공유해 작업하기 때문에 서로의 작업에 영향을 주게 된다. 스레드A가 작업하던 도중에 다른 스레드B에게 제어권이 넘어갔을 때, 스레드A가 작업하던 공유자원을 스레드B가 임의로 변경한다면, 다시 스레드A로 제어권이 넘어가 작업을 마쳤을 때 의도했던 것과 다른 결과를 얻게 된다.

따라서 스레드가 특정 작업을 끝마치기 전까지 다른 스레드에 의해 방해받지 않도록 하는 것이 필요하다.

한 스레드가 진행중인 작업을 다른 스레드가 간섭하지 못하도록 막는 것이다.

 

이용 방법

1) 메소드 전체를 임계 영역으로 지정

    public synchronized void calcSum(){   }

2) 특정 영역을 임계 영역으로 지정

    synchronized (객체의 참조변수){   }

 

package review;

public class Re07 {
	static Data sharedData = new Data();
	public static void main(String[] args) {
		System.out.println("> 메인 시작");

		Tom t = new Tom();
		Jane j = new Jane();
		t.start();

		j.start();
		System.out.println("main 종료");

	}

}
class Data{
	public int i = 0;
}

class Tom extends Thread{

	@Override
	public void run() {
		synchronized (Re07.sharedData) {
			for (int i = 0; i <10000; i++) {
				Re07.sharedData.i++;
			}
			System.out.println(">Tom i = "+Re07.sharedData.i);
		}
	}

}

class Jane extends Thread{

	@Override
	public void run() {
		synchronized (Re07.sharedData) {


			for (int i = 0; i <10000; i++) {
				Re07.sharedData.i++;
			}
			System.out.println(">Jane i = "+Re07.sharedData.i);
		}
	}

}

 

만일 이 코드에서 synchronized를 주지 않았다면 Tom i 값과 Jane i 값이 계속 변경된다.  공유자원이 제어권에 의해 바뀌기 때문이다. 

+ 동기화를 하지 않고 main에 다음 코딩을 삽입해도 무방하다.

		t.start();	
        
		try {
			t.join(); 
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
        
		j.start();	
		

t.join에 의해  main스레드가 t가 끝날때까지 기다린다. 

t스레드가 일을 마친 다음에야 main으로 넘어가서 j를 스타트시키는 것이다.

 

 

다음은 동기화의 두번째 예제 박씨의 잔고이다.

package review;

public class Re08 {
	static Bank myBank = new Bank();
	public static void main(String[] args) {
		System.out.println("> 원금:"+ Re08.myBank.getMoney());

		Park p = new Park();
		ParkWife pw = new ParkWife();

		p.start();

		try {
			Thread.sleep(2000); //박씨가 입금한지 2초 후 와이프가 출금
		} catch (InterruptedException e) {
			e.printStackTrace();
		} 
		pw.start();

	}

}
class Bank{
	private int money = 3000;

	//게터세터
	public int getMoney() {
		return money;
	}

	public void setMoney(int money) {
		this.money = money;
	}

	//메소드
	//입금
	public void saveMoney(int save) {
		int m = this.getMoney();
		try {
			Thread.sleep(3000); //입금하는데 3초
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.setMoney(m+save);
	}
	//출금
	public void minusMoney(int minus) {
		int m = this.getMoney();
		try {
			Thread.sleep(2000); //출금하는데 2초
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.setMoney(m-minus);
	}

}

class Park extends Thread{ //입금하는 박씨

	@Override
	public void run() {
		Re08.myBank.saveMoney(3000); //3천원 입금
		System.out.println("> saveMoney(3000) : " + Re08.myBank.getMoney());
	}

}

class ParkWife extends Thread{

	@Override
	public void run() {
		Re08.myBank.minusMoney(5000); //5천원 출금
		System.out.println(">minusMoney(5000)" + Re08.myBank.getMoney());
	}

}

출력값은 동기화를 하지 않아 다른 값이 나온다.

동기화 처리를 한 후에는 제대로 된 값이 나올 것이다. (두 부분 수정)

public void minusMoney(int minus) {
		synchronized (this) {
		int m = this.getMoney();
		try {
			Thread.sleep(2000); //출금하는데 2초
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.setMoney(m-minus);
		}
	}
}


Class Park extends Thread{ //입금하는 박씨

	@Override
	public void run() {
		synchronized (Re08.myBank) {
		Re08.myBank.saveMoney(3000); //3천원 입금
		System.out.println("> saveMoney(3000) : " + Re08.myBank.getMoney());
		}
	}
}

반응형

'Java' 카테고리의 다른 글

[days28] InetAddress 클래스  (0) 2020.11.01
[days27] 스레드 그룹과 데몬스레드  (0) 2020.10.27
[days27] 스레드 강제종료  (0) 2020.10.27
[days26] 스레드 - 동기화의 필요성  (1) 2020.10.26
[days26] 스레드 예제  (0) 2020.10.26
Comments