본문 바로가기

언어/Java

스레드 동기화

멀티 스레드는 하나의 객체를 공유해서 작업할 수도 있다. 이 경우, 다른 스레드에 의해 객체 내부 데이터가 쉽게 변경될 수 있기 때문에 의도했던 것과는 다른 결과가 나올 수 있다.

↓ :  시간의 흐름

시간의 흐름상 그림은 50이 출력, 내가 의도한 것과 다른 결과가 나올 수 있다

User1Thread는 Calculator 객체의 memory 필드에 100을 먼저 저장하고 2초간 일시 정지 상태가 된다.

그동안 User2Thread가 memory 필드값을 50으로 변경한다. 2초가 지나 User1Thread가 다시 실행상태가 되어

 memory 필드의 값을 출력하면 User2Thread가 저장한 50이 나온다.

User1Thread에 저장된 데이터가 날아가버림. 스레드가 사용 중인 객체를 다른 스레드가 변경할 수 없도록 하려면 스레드 작업이 끝날 때까지 객체에 잠금을 걸면 된다. 이를 위해 자바는 동기화(synchronized) 메소드와 블록을 제공한다.

 

package ch14.sec06.exam01;

public class Calculator {
	private int memory;

	public int getMemory() {
		return memory;
	}

	public synchronized void setMemory1(int memory) { // 메서드 자체에 잠금장치 가능
		this.memory = memory;
		try {
			Thread.sleep(2000);
		} catch(InterruptedException e) {}
		System.out.println(Thread.currentThread().getName() + ": " + this.memory);
	}

	public void setMemory2(int memory) {
		synchronized(this) { // 메서드 내부에서 잠금장치 가능, 이렇게 블럭쓰는걸 더 권장
			this.memory = memory;
			try {
				Thread.sleep(2000);
			} catch(InterruptedException e) {}
			System.out.println(Thread.currentThread().getName() + ": " + this.memory);
		}
	}
}

setMemory1과 setMemory2는 하나의 스레드만 실행 가능한 메소드가 된다.

synchronized 키워드는 인스턴스와 정적 메소드 어디든 붙일 수 있다.

스레드가 동기화 메소드를 실행하는 즉시 객체는 잠금이 일어나고, 메소드 실행이 끝나면 잠금이 풀린다.

 

※ Vector 여러 스레드 사이에서의 공유객체 - 이미 동기화됨, 여러 스레드 사이에서 공유객체로 쓰인다
※ ArrayList는 수정할 때마다 synchrozied 블럭 직접 만들어줘야함, 속도 저하, 여러 스레드 사이에서 공유객체로 안쓰일때 사용

 

※ wait()과 notify()를 이용한 스레드 제어

두 개의 스레드를 교대로 번갈아 가며 실행해야 할 때, 공유 객체를 사용한다.

공유 객체는 두 스레드가 작업할 내용을 각각 동기화 메소드로 정해 놓는다. 한 스레드가 작업을 완료하면 notify() 메소드를 호출해서 일시 정지 상태에 있는 다른 스레드를 실행 대기 상태로 만들고, 자신은 두 번 작업을 하지 않도록 wait() 메소드를 호출하여 일시 정지 상태로 만든다.

 

notify()는 wait()에 의해 일시 정지된 스레드 중 한개를 실행 대기 상태로 만들고, notifyAll()은 wait()에 의해 일시 정지된 모든 스레드를 실행 대기 상태로 만든다. 이 두 메소드는 동기화 메소드 또는 동기화 블록 내에서만 사용 가능하다.

 

wait() notify(synchrozied) : 공유객체를 사용하고있는 블럭에서 효과

공유객체에 wait, notify 메소드 사용됨, Thread에 있는게 아님

'언어 > Java' 카테고리의 다른 글

네트워크  (0) 2023.08.16
스레드 안전 종료  (0) 2023.08.16
스레드 상태  (0) 2023.08.16
스레드 이름 부여하기  (0) 2023.08.16
Thread pop, push  (0) 2023.08.16