JAVA

멀티쓰레드 프로그래밍 multi-thread programming

Stater 2019. 10. 28. 17:38

멀티쓰레드 프로그래밍

임계영역(critical section)

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

- critical section에 동시에 thread가 접근하게 되면 실행 결과를 보장 할 수 없음

- thread간의 순서를 맞추는 동기화(synchronized)이 필요

 

동기화(synchronized)

- 임계 영역에 여러 thread가 접근하는 경우 한 thread가 수행 하는 동안 공유 자원을 lock하려

  다른 thread의 접근을 막음

 

- 동기화를 잘못 구현하면 deadlock에 빠질 수 있음

 

자바에서 동기화 구현

- synchronized수행문과 synchronized 메서드를 이용

 

1. synchronized 수행문

 

synchronized(참조형 수식){

 

}

 

참조형 수식에 해당되는 개체에 lock을 건다.

 

2. synchronized 메서드

- 현재 이 메서드가 속해 있는 객체에 lock를 건다.

sychronized메서드 내에서 다른 synchronized 메서드를 호출하지 않는다.(deadlock 방지를 위해)

 

문제 발생시점

- static를 가지고 있는 변수들의 자원들을 공유하면서 멀티쓰레드에 관련된 문제가 발생 될 수 있다.

 

package thread;
class Bank {
	private int mony = 10000;
	
	public void saveMoney(int save) {
		int m = this.getMony();
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		setMony(m+save);
	}
	
	public void minusMoney(int minus) {
		int m = this.getMony();
		
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		setMony(m-minus);
	}

	int getMony() {
		return mony;
	}

	private void setMony(int mony) {
		this.mony = mony;
	}
}

class Park extends Thread{
	
	public void run() {
		System.out.println("Start Save");
		SyncTest.myBank.saveMoney(3000);
		System.out.println("Start End"+"savemoney"+SyncTest.myBank.getMony());
	}
}

class ParkWife extends Thread{
	public void run() {
		System.out.println("Start minus");
		SyncTest.myBank.minusMoney(1000);
		System.out.println("Start End"+"minusmoney"+SyncTest.myBank.getMony());
	}
}
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();

	}

}

 

위의 코드는 동기화가 안되어 나온 결과 값

Start Save
Start minus
Start Endminusmoney9000
Start Endsavemoney13000

 

동기화가 적용된 코드

package thread;
class Bank {
	private int mony = 10000;
	
	public synchronized void saveMoney(int save) {
		int m = this.getMony();
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		setMony(m+save);
	}
	
	public synchronized void minusMoney(int minus) {
		int m = this.getMony();
		
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		setMony(m-minus);
	}

	int getMony() {
		return mony;
	}

	private void setMony(int mony) {
		this.mony = mony;
	}
}

class Park extends Thread{
	
	public void run() {
		System.out.println("Start Save");
		SyncTest.myBank.saveMoney(3000);
		System.out.println("Start End"+"savemoney"+SyncTest.myBank.getMony());
	}
}

class ParkWife extends Thread{
	public void run() {
		System.out.println("Start minus");
		SyncTest.myBank.minusMoney(1000);
		System.out.println("Start End"+"minusmoney"+SyncTest.myBank.getMony());
	}
}
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();

	}

}

위의 코드는 동기화가 적용되어 나온 결과 값

Start Save
Start minus
Start Endsavemoney13000
Start Endminusmoney12000

 

Synchronized  수행문을 적용한 것과 synchronized 메서드를 적용한 수행문

package thread;
class Bank {
	private int mony = 10000;
	
	public void saveMoney(int save) {
		synchronized(this) {
			int m = this.getMony();
			
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			setMony(m+save);
		}
	}
	
	public synchronized void minusMoney(int minus) {
		int m = this.getMony();
		
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		setMony(m-minus);
	}

	int getMony() {
		return mony;
	}

	private void setMony(int mony) {
		this.mony = mony;
	}
}

class Park extends Thread{
	
	public void run() {
		System.out.println("Start Save");
		SyncTest.myBank.saveMoney(3000);
		System.out.println("Start End"+"savemoney"+SyncTest.myBank.getMony());
	}
}

class ParkWife extends Thread{
	public void run() {
		System.out.println("Start minus");
		SyncTest.myBank.minusMoney(1000);
		System.out.println("Start End"+"minusmoney"+SyncTest.myBank.getMony());
	}
}
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();

	}

}

 

run() 부분에 lock을 걸어봤자 소용이 없다.

쓰레드 부분에 락을 건 것이 아니기 떄문에 소용이 없다.

- public synchronized void run(){

     

}

이 부분에 락을 걸고 싶을 경우에는 블락 방식으로 적용시켜주면 가능하다.

-

public void run(){

synchronized(SyncTest.myBank){

코드

}

}
반응형

'JAVA' 카테고리의 다른 글

Chapter01. 변수  (0) 2023.02.23
멀티쓰레드 프로그래밍 multi-thread programming  (0) 2019.10.29
Thread status ( 쓰레드 상태 ) -활용  (0) 2019.10.27
Thread class  (0) 2019.10.26
입출력 클래스 및 데코레이터패턴  (0) 2019.10.25