동기화 처리를 위한 자바 키워드로 특정 영역을 단일 스레드 환경으로 만드는 것
synchronized 동기화 처리란 특정 스레드가 작업 중에는 다른 스레드들이 작업에 참여할 수 없게 하는 것이다.( 단일 스레드 환경 )
여러 스레드가 하나의 자원을 공유해서 사용할 때 -> 멀티 스레딩시 synchronized 동기화 처리를 하면 공유 정보에 대한 안전성과 신뢰성을 높인다. ( thread-safe )
예)여러 고객들이 영화 좌석을 예매할 때 예매시점에서는 동일한 좌석을 예매하는 상황을 방지하기 위해 단일 스레드 환경으로 처리
예) 여러 손님들이 카페 하나의 화장실을 이용할 때 그 시점에서는 동시에 사용할 수 없으므로 단일 스레드 환경으로 처리
멀티 스레딩시 이런 예에서 특정 영역에서는 반드시 단일 스레드 환경으로 처리해야 하는 경우 synchronized keyword를 이용한다.
메서드 단위에서 동기화처리
ex) public synchronized void reserve(){}
특정 영역 단위에서 동기화 처리
ex) public void reserve(){
synchronized(this){
}
}
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
이렇게 메소드 단위에서 동기화 처리하면 단일 스레드 환경으로 실행되는 결과를 볼 수 있다.
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) 처럼 한 스레드가 이 메소드 내의 한 영역을 동기화 시켜 단일 스레드 환경으로 만들고 그 영역을 실행할때는 다른 스레드가 기다리게해 동시 실행을 막을 수 있다는 것이다.