쓰레드 동기화 (synchronized)

기록하는 용도·2022년 9월 4일
0

동기화 (synchronized)

동기화 처리를 위한 자바 키워드로 특정 영역을 단일 스레드 환경으로 만드는 것

동기화 처리

synchronized 동기화 처리란 특정 스레드가 작업 중에는 다른 스레드들이 작업에 참여할 수 없게 하는 것이다.( 단일 스레드 환경 )
여러 스레드가 하나의 자원을 공유해서 사용할 때 -> 멀티 스레딩시 synchronized 동기화 처리를 하면 공유 정보에 대한 안전성과 신뢰성을 높인다. ( thread-safe )

예)여러 고객들이 영화 좌석을 예매할 때 예매시점에서는 동일한 좌석을 예매하는 상황을 방지하기 위해 단일 스레드 환경으로 처리

예) 여러 손님들이 카페 하나의 화장실을 이용할 때 그 시점에서는 동시에 사용할 수 없으므로 단일 스레드 환경으로 처리

멀티 스레딩시 이런 예에서 특정 영역에서는 반드시 단일 스레드 환경으로 처리해야 하는 경우 synchronized keyword를 이용한다.

동기화 처리 방법

  1. 메서드 단위에서 동기화처리
    ex) public synchronized void reserve(){}

  2. 특정 영역 단위에서 동기화 처리
    ex) public void reserve(){
    synchronized(this){

      }
    }	

예제1

public class TestThread10 {
	public static void main(String[] args) {
		Toilet toilet=new Toilet();
		Thread thread1=new Thread(toilet,"김씨");
		Thread thread2=new Thread(toilet,"이씨");
		thread1.start();
		thread2.start();
	}
}
public class Toilet implements Runnable{
	// 멀티 스레딩시 공유되는 인스턴스 변수 즉 객체의 정보 
	private String room="1번 화장실칸";
	@Override
	public void run() {
		String threadName=Thread.currentThread().getName();
		try {
			use(threadName);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	// 화장실을 사용하는 메서드는 멀티 스레드가 아니라 
	// 단일 스레드 환경으로 실행된다 ( Thread1 실행완료 -> Thread 2 ... ) 
	public synchronized void use(String userName) throws InterruptedException {
		System.out.println(userName+" 입장");
		Thread.sleep(2000);
		System.out.println(userName+"님 "+room+" 사용중");	
		Thread.sleep(2000);
		System.out.println(userName+" 나감");
	}
}

김씨 입장
김씨님 1번 화장실칸 사용중
김씨 나감
이씨 입장
이씨님 1번 화장실칸 사용중
이씨 나감

동기화 처리 synchronized 의 필요성을 확인하는 예제이다.
만약 화장실이 하나 있는 어느 카페의 두명의 손님이 있을때, 그 두 명이 화장실을 동시에 이용할 수는 없을것이다. 한사람이 화장실을 사용하고 나오면, 그제서야 다음 사람이 사용할 수 있을 것이다.
이렇게 여러 스레드가 하나의 자원을 공유할 때 멀티 스레딩시 특정 업무 처리 영역에서는 단일 스레드 환경으로 만들어 실행시켜야 한다.

public synchronized void use(String userName) throws InterruptedException

이렇게 메소드 단위에서 동기화 처리하면 단일 스레드 환경으로 실행되는 결과를 볼 수 있다.

예제2)

public class TestThread11 {
	public static void main(String[] args) {
		Theater theater=new Theater();
		new Thread(theater,"김씨").start();
		new Thread(theater,"이씨").start();
	}
}
public class Theater implements Runnable{
	private int seat=1; // 멀티 스레드 공유 자원 

	@Override
	public void run() {
		String threadName=Thread.currentThread().getName();
		try {
//			reserve(threadName);
			reserve2(threadName);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	// 동일한 좌석이 예매될 수 있다 
	public void reserve(String customer) throws InterruptedException {
		Thread.sleep(100);
		System.out.println(customer+"님 "+seat+"번 영화좌석예매");
		Thread.sleep(100);
		seat++;
	}	
	public void reserve2(String customer) throws InterruptedException {
		Thread.sleep(100);
		//아래 영역만 동기화해서 단일 스레드 환경으로 만든다 
		synchronized (this) {
			System.out.println(customer+"님 "+seat+"번 영화좌석예매");
			seat++;
		}		
		Thread.sleep(100);		
	}
}

김씨님 1번 영화좌석예매
이씨님 2번 영화좌석예매

위와 같이 멀티 스레딩시 동기화 처리 예제이다.
여러 고객 ( 스레드 ) 들이 공유자원인 극장 좌석을 예매할 때 예매 지점에서는 동시에 실행되어 동일한 좌석이 예매되지 않도록 동기화 처리를 해서 단일 스레드 환경으로 만드는 예제이다.

만약 주석 처리 해둔 reserve(threadName) 메소드를 실행시킨다면 동일한 좌석이 예매될 수 있다. 두개의 쓰레드가 동시에 실행되기때문에 seat이 ++ 되기도 전해 같은 좌석 번호를 가진 자리를 동시에 예매될 수 있다는 것이다.
이를 방지하기위해 reserve2(threadName) 처럼 한 스레드가 이 메소드 내의 한 영역을 동기화 시켜 단일 스레드 환경으로 만들고 그 영역을 실행할때는 다른 스레드가 기다리게해 동시 실행을 막을 수 있다는 것이다.

0개의 댓글