Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

Super Coding Addict

Ch15. 자바 Thread 프로그래밍 (4) - multi-thread 프로그래밍 본문

JAVA 문법

Ch15. 자바 Thread 프로그래밍 (4) - multi-thread 프로그래밍

밍응애 2021. 2. 14. 19:04

< multi-thread 프로그래밍 >

* critical section (임계 영역)

- 두개 이상의 thread가 동시에 접근하게 되는 리소스

- 동시에 여러 개의 thread가 이 영역에 접근하게 되면 실행 결과 보장 불가

--> 따라서 thread간 순서를 맞추는 동기화(syncronization)이 필요!!

 

  • Java에서 공유자원이 되는 것은 static 키워드를 가진 객체라고 보면 됨

* 동기화 (syncronization)

- 임계영역에 여러 thread가 접근하는 경우, 한 thread가 수행하는 동안에 임계영역 안의 공유자원을 lock해서 다른 thread의 접근을 막음

- 동기화 잘못 구현시 deadlock에 빠질 수 있음

 

 

* Java에서 동기화 구현

- synchronized 수행문 / synchronized 메서드 이용

- deadlock을 효과적으로 막는 기능은 제공하지 않지만, synchronized 메서드 내에서 다른 synchronized 메서드 호출 X

 

- 예제

# SyncTest 클래스

package ch15.thread;

class Bank{
	private int money = 10000;
	
	public void saveMoney(int save) {
		int m = this.getMoney();
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		setMoney(m + save);
	}

	public void minusMoney(int minus) {
		int m = this.getMoney();
		
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		setMoney(m - minus);
	}
	
	public int getMoney() {
		return money;
	}

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

class Park extends Thread{
	public void run() {
		System.out.println("start save");
		SyncTest.myBank.saveMoney(3000);
		System.out.println("save money: " + SyncTest.myBank.getMoney());
	}
}

class ParkWife extends Thread{
	public void run() {
		System.out.println("start minus");
		SyncTest.myBank.minusMoney(1000);
		System.out.println("minus money: " + SyncTest.myBank.getMoney());
	}
}

public class SyncTest {

	public static Bank myBank = new Bank();
	
	public static void main(String[] args) throws InterruptedException {
		
		Park p = new Park();
		p.start();
		
		Thread.sleep(200);

		ParkWife pw = new ParkWife();
		pw.start();
		
	}

}

 

--> 기존에 있는 돈은 10000원, 여기에 박씨가 3000원을 저금하고 박씨 와이프가 1000원을 인출하면 예상결과는 12000원

--> 여기서 critical section이 Bank, 공유자원은 money이다.

 

--> 그러나 결과는 13000원이 되었다. 왜 이런 결과가 나타났을까?

--> main을 보면, 먼저 박씨 Thread가 시작되고 0.2초 sleep을 한 후 박씨 와이프의 Thread가 시작된다

     이 때 박씨 Thread의 run은 saveMoney 메서드를 호출하는데,

     이처럼 saveMoney메서드는 먼저 기존의 돈을 가져오고 3초 sleep한 뒤 기존의 돈에 저축한 돈을 더하게 된다.

     3초가 sleep하는 동안 main에서 0.2초만 sleep하고 박씨 와이프의 Thread가 실행, minusMoney 메서드가 호출된다.

      minusMoney메서드는 기존의 돈을 가져오는 데, 아직 박씨의 Thread는 sleep중이므로 저축이 완료되지 않았고,

      따라서 가져온 돈은 저축 후의 금액인 13000원이 아니라, 기존 금액인 10000원이므로 계산 결과는 9000원이 된다.

 

==> 이처럼 원치 않은 결과가 나오지 않도록 동기화를 사용해야 하는 것이다.

 

--> 이렇게 메서드에 synchronized를 걸어주면(synchronized 메서드방식), class인 Bank에 lock이 걸리게 되고, 먼저 임계영역에 접근하는 Thread의 수행이 끝날 때까지 다른 Thread는 Bank에 접근 불가

 

--> 이제 박씨 수행이 끝날 때까지 박씨 와이프는 Bank에 접근 불가

 

--> 이처럼 동기화 후에는 원하는 결과인 12000원을 얻을 수 있다.

 

cf. synchronized 블럭 수행문

 

cf. 만약 run() 안에 synchronized 블럭을 사용하게 된다면?

 

--> 결과는 아까와는 조금 다르게 이번에는 메서드 자체에 걸은 게 아니고 myBank 전체에 걸어버렸으므로 진입자체가 불가해 start minus가 save가 완전히 끝나고 찍힘