멀티 스레드 환경에서 여러 스레드가 동시에 데이터에 접근한다면 의도하지 않은 결과가 발생할 수 있다.
이러한 이유로 synchronized
는 공유된 가변 데이터를 보호하기 위하여 사용된다.
보호하는 방법은 단순히 동기화처리하여 한 자원에 한 스레드만 동시에 접근할 수 있게 하는 것이다.
synchronized
를 사용하는 방법은 다음과 같다.
public synchronized void method(){}
public static synchronized void method(){}
// 메소드 안에서
synchronized(this) {}
synchronized
가 적용된 구문을synchronized block
이라고 한다.
멀티 스레드 환경에서 동기화로 Race condition을 해결해준다는 장점이 있지만, 성능이 크게 저하될 수 있으니 적재적소에 사용해야한다.
다음은 synchronized
의 동기화 방법들이다.
public synchronized void method(){}
메소드에 synchronized
를 적용하기 때문에 해당 메소드만 동기화 된다고 착각할 수 있다.
하지만 인스턴스 메소드 동기화는 해당 메소드에 접근하면 끝날때까지 인스턴스 접근을 아예 막는다.
예를 들어 한 스레드가 어떠한 인스턴스의 synchronized
가 적용된 메소드1 수행을 시작했다면, 다른 스레드는 메소드2를 수행하고 싶어도 대기한다.
즉, 하나의 인스턴스를 동기화할 수 있다.
public static synchronized void method(){}
인스턴스 메소드 동기화가 하나의 인스턴스를 동기화 시켰다면, 스태틱 메소드 동기화는 해당 객체 전체를 동기화 시킨다.
예를 들어 하나의 클래스를 찍어낸 여러 인스턴스가 존재하고, 인스턴스1이 syncronized
가 적용된 메소드를 수행 시작했다면, 다른 스레드에서 인스턴스2를 사용하고 싶어도 대기한다.
즉, 동일한 클래스로 만들어진 여러 인스턴스들을 모두 동기화할 수 있다.
// 메소드 안에서
synchronized(this) {}
위 두 방법들은 인스턴스 하나 혹은 전체를 동기화시켜 비효율적이다.
메소드 안 동기화 방법을 사용하면 synchronized
구문에서 사용된 멤버 필드를 접근하는 경우에만 동기화한다.
예를 들어 한 스레드가 인스턴스의 멤버 필드 number
을 증가시키는 synchonized
구문을 실행한다면
다른 스레드는 해당 인스턴스의 number
을 감소시키는 메소드는 실행하지 못하고 대기하지만, number
에 접근하지 않는 메소드는 대기 없이 실행 가능하다.