티스토리 뷰

Java/개념

JAVA 동기화

정복잉 2020. 7. 14. 03:10
반응형
package day19;

public class Thread10 { //메인 클래스
	public static void main(String[] args) {
		Runnable r = new Money(); //쓰레드를 호출한 클래스 객체화
		new Thread(r).start(); //쓰레드 실행A
		new Thread(r).start(); //쓰레드 실행B
	
	}

}

class Account {
	private int balance = 1000; //은행잔고
	public String name;

	public int getBalance() {  //호출을 하기 위해 get 설정, 수정할 이유X set 설정X
		return balance;
	}
	
	public synchronized void withdraw(int money) {
		if(balance >= money) {
			try {Thread.sleep(1000);} catch (InterruptedException e) {} //Thread sleep
			balance -=money; //출금
		}
	} //withdraw 메서드 라인
} //Account 클래스 라인

class Money implements Runnable{ //Runnable을 사용하는 이유 : 멀티쓰레드를 사용하기 위해
	Account acc = new Account(); //클래스 객체화
	public void run() {   //쓰레드 설정
		while(acc.getBalance()>0) { //은행잔고의 잔액이 존재할 경우 반복문 실행
			int money = (int)(Math.random()*3+1)*100 ; //100,200,300 중 출금할 예정
			acc.withdraw(money);// 랜덤으로 withdraw 메서드를 이용하여 출금
			System.out.println("잔액 : "+acc.getBalance()); //출금 후 잔액 표시
		}
	} //run
}  //Money 클래스 라인 

synchronized

package day19;

public class Thread11 {
	public static void main(String[] args) {
		ThreadF f = new ThreadF();
		f.start();
		
		synchronized (f) {
			try {
				System.out.println("f가 완료될때까지 기다립니다.");
				f.wait();
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("Total is :"+f.total);
		}
		
	}

}
class ThreadF extends Thread {
	int total;
	
	public void run() {
	synchronized (this) {
		for(int i=0;i<5;i++) {
			System.out.println(i+"를 더합니다.");
			total +=i;
			
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		notify(); //중단된 쓰레드가 락을 다시 얻어 작업을 한다.
	}
	}
	
}

wait( ) 와 notify( )

※개념정리

멀티쓰레드의 경우 작업의 의도와 결과가 다르게 되는 것을 방지하기 위해  하나의 쓰레드가 특정작업을 마치기 전까지 다른 쓰레드한테 방해받지 않기 위해 '임계영역'과'락'을 정의했다.

임계영역 : 공유데이터를 사용하는 코드 영역

임계영역을 지정한 쓰레드는 공유데이터가 가지고 있는 락을 획득하여 단 하나의 쓰레드만 코드를 수행할 수 있으며,

반납시 다른 스레드가 락을 획득해야 임계영역을 수행할 수 있다.

동기화 : 한 쓰레드가 진행중인 작업을 다른 쓰레드가 간섭하지 못하도록 막는 것

 

동기화 방법

1)  synchronized

1. 메서드 앞에 synchronized을 붙인다.
public synchronized void cal() {
//... 임계영역
}

2.특정한 영역을 임계영역으로 지정 (추천)
synchronized(객체의 참조변수) {
//... 임계영역
}

임계영역은 멀티쓰레드의 프로그램 성능을 좌우하므로 메서드 전체보단 synchronized블럭으로 임계영역을 최소화 하는 것이 효율적이다.

2) wait( ), notify( ),  notifyAll( )

특정쓰레드가 객체의 락을 가진 상태로 오랜 시간을 보내지 않는게 중요

synchronized블록에서 존재하며, wait( )에 의해 lock을 반납했다가 다시 lock를 얻어서 임계영역을 들어오는 것을 재진입이라고 한다.

wait( ) 의 매개변수가 있을 경우 그 시간이 지난후에 자동으로  notify( )가 호출된다.

notify( )가 호출되면, 해당 객체의 대기실에 있던 모든 쓰레드 중에 임의의 쓰레드만 호출

notifyAll( )가 호출되면, 기다리고 있는 모든 쓰레드가 호출

댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   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
글 보관함