상세 컨텐츠

본문 제목

JAVA Thread synchronized 쓰레드 동기화, wait() notify()

BackEnd/JAVA

by H_Develop 2022. 8. 3. 12:43

본문

휴대폰으로 음악이나 영상을 동기화 하게 되면, 동기화가 끝날 때 까지 휴대폰은 다른 작업을 할 수가 없는데,
이런 구조가 바로 동기화 쓰레드의 구조이다.
두개 이상의 쓰레드가 하나의 자원을 공유할 경우, 동기화 문제가 발생된다.
변수는 하나인데 두 개의 쓰레드가 동시에 한 변수의 값을 변경하려하면 오류가 발생한다.
이를 막기 위해서 내가 컴퓨터로 작업을 하다가, 잠시 자리를 비운 사이 내 작업이 끝날 때 까지,
다른 사람이 손대지 못하도록 컴퓨터를 잠가둘 필요가 있다.

이처럼 특정 쓰레드들이 공유하는 한 개의 자원을 사용 중일 때,
이 작업이 끝날 때 까지 다른 쓰레드가 이 자원을 공유해서 작업하지 못할게 할 때, 동기화가 필요하다.

JAVA 에서 getter(얻어오는 것) 와 setter(설정)
 객체 지향 프로그래밍에서 객체의 데이터는 객체 외부에서 직접적으로 접근하는 것을 막는데,
객체 데이터를 외부에서 읽고 변경하면 객체의 무결성(ie, 자동차의 속도가 마이너스, 말이 안되는 것들)이
깨질 수 있기 때문이다.
 따라서 객체 지향 프로그래밍에서는 메서드를 통해 데이터를 변경하는 방법을 선호한다.
데이터는 외부에서 접근하지 못하게 하고 메서드는 공개해서 외부에서 메서드를 통하게 해서 데이터에 접근시킨다.
이런 메서드가 Setter이다.
 또한 객체 외부에서 객체 필드 값을 사용하지 못하게 할 수도 있는데, 
이럴 때는 메서드로 필드 값을 가공해서 외부로 전달하는데 이렇게 해서 값을 가져오는 메서드가 Getter이다.
 - 클래스를 선언할 때, 가능하면 필드 맴버들을 private로 선언해서 외부로부터 보호하고,
 필드에 대한 Setter / Getter 메서드를 작성해서 필드 값을 안전하게 변경 / 사용하는 것이 좋다.

 

 

 

Synchronized

 

class SyncEx implements Runnable {	
	private long money = 10_000;	// 잔액
	
	@Override
	public void run() {				
		synchronized (SyncEx.class) {	// SyncEx.class는 this, 동기화 한다.
// synchronized 키워드를 사용하면, 해당 키워드가 명시되어있는 영역의 처리가 마무리 될 때까지
// 다른 쓰레드에서 접근하지 못하게 된다.
			for(int i=0; i<10; i++) {
				try {
					Thread.sleep(500);
				} catch (Exception e) {	e.printStackTrace(); }
				if (getMoney() <= 0) {break;}
				outMoney(1000);
			}
		}
	}
	
	public long getMoney() {			// Getter() 메서드 설정
		return money;
	}
	public void setMoney(long money) {	// Setter() 메서드 설정
		this.money = money;
	}
	public void outMoney(long howMuch) {
		String threadName = Thread.currentThread().getName();
		if (getMoney() > 0) {	// 잔액이 남아 있다면,
			money -= howMuch;	// 출금액.
			System.out.println(threadName + " - 잔액 : " + getMoney() + " 원");
		} 
		if (getMoney() == 0) {
			System.out.println(threadName + " - 잔액이 없어요");
		}
	}
}

public class ex1 {
	public static void main(String[] args) {
		SyncEx atm = new SyncEx();
		Thread mom = new Thread(atm, "엄마");
		Thread son = new Thread(atm, "아들");
		
		mom.start();	// start()를 실행하면, 내부적으로 run()이 실행되므로 위의 run() orverride 에러가 없음.
		son.start();
		
	}
}

 

 

 

쓰레드에서 wait()와 notify()
현재 실행중인 쓰레드가 진행 중에, wait() 메서드를 만나면 일시적으로 정지되어
해당 쓰레드가 일시적으로 대기상태로 보내지고, 다른 쓰레드에게 제어권을 넘긴다.
그리고 wait()를 만나 대기상태에 빠진 쓰레드는 notify()를 만나면 재 구동된다.
이런 기법을 이용하면, 두 개 이상의 쓰레드가 구동 중일 때, 한 개의 동기화 쓰레드가 작업을 진행하면
이 작업을 완전히 마칠 때까지 기다렸다가 다른 쓰레드의 작업이 수행되는 것이 아니라,
하나의 쓰레드 동기화가 진행 중일 때에도 일시적으로 해당 쓰레드를 정지시키고 
다른 쓰레드가 작업을 할 수 있게 만들 수 있다.

'BackEnd > JAVA' 카테고리의 다른 글

JAVA 다형성(Polymorphism)  (0) 2022.08.04
JAVA Lambda 람다식  (0) 2022.08.04
JAVA Thread (Daemon, join() )  (0) 2022.08.03
JAVA Thread run() start()  (0) 2022.08.01
JAVA JFrame / Exception 예외처리 / printStackTrace()  (0) 2022.08.01

관련글 더보기