동기화(Synchronization)
thread 들이 field 들에 대해 access 를 공유하면서 발생하는 문제가 2가지
- Thread interference
- Memory inconsistency
Thread Interference
라는 동작도 jvm 에서는 3가지 step 으로 바뀔 수 있다.
c++
- c 의 값을 가져오고
- 가져온 값을 1 증가 시키고
- c 에 새로운 값을 저장한다.
만약 Thread A 와 Thread B 가 1step 씩 차례로 동작하게 된다면
- c 의 값을 가져오고(A)
- c 의 값을 가져오고(B)
- 가져온 값을 1 증가 시키고(A)
- 가져온 값을 1 감소 시키고(B)
- c 에 새로운 값을 저장한다.(A)
- c 에 새로운 값을 저장한다.(B)
Memory consistency errors
이 녀석이 일어나는 상황은 복잡해서 문서에서 설명하지 않는다. 프로그래머는 이 memory consistency errors를 피하는 방법만 알면 된다고 이야기 한다.이 memory consistency errors 를 피하는 핵심적인 방법은 happens-before 관계를 이해 하는 것이다.
int c = 0 ;이 있다고 하자. 만약 thread A 가
c++를 실행하고, thread B 가
System.println.out(c);를 하면, Thread A 가 먼저 실행이 된다면, 화면에는 '1' 이 찍힐 것이고, Thread B 가 Thread A 보다 먼저 실행된다면 화면에는 '0' 이 찍힐 것이다.
프로그래머가 이 두 개의 statement 사이에 happens-before relationship 을 만들기 전에는 Thread A 가 Thread B 보다 먼저 실행된다는 것을 보장할 수 없다. 우리나라 말로 풀이한다면 "미리 일어나는", "선행" 정도의 의미가 되겠다.
이 happens-before relationships 를 만드는 방법이 몇 가지 있다. 그 중 하나가 synchronization 이다.
happens-before relationship 의 예는 Thead.start() 와 Thread.join() 에서도 볼 수 있다.
- start 는 그 시점부터 thread 가 시작하는 것이기 때문에 그 이전의 statement 와 happens-before 관계 가 되는 것이고,
- join 은 thread 가 끝날 때까지 기다려 주는 것이기 때문에, join 이후에 실행되는 statement 들은 그 이전의 statement 와 happens-before relationship 이 되는 것이다.
java 에서는
- syncrhronized statement
- synchronized method
Synchronized method
public synchronized void increment() {위 처럼 synchronized 를 사용하면 된다.
c++;
}
synchronized method 에는 2가지 효과가 생긴다.
같은 object(instance) 에서 synchronized method 에 대해 간섭할 수 있는(interleave) 2개의 호출이 불가능하다.
만약 thread A 가 synchronized method 를 사용하고 있는데, thread B 가 호출을 한다면, thread B 는 thread A 가 끝날 때까지 기다려야 한다. (block)
synchronized method 가 존재하면, 자동적으로 synchronized 호출들 간에 happens-before 관계를 만든다. 이것은 모든 thread 가 object 의 상태의 변화를 아는 것을 보장한다.(guarantee the visiblility)
Intrinsic lock and Synchronization
Synchronization 은 intrinsic lock 또는 monitor lock 으로 알려진 내부요소를 이용해서 만들어졌다.thread 가 synchronized method 를 호출 할 때, method 의 object 의 intrinsic lock 을 자동으로 acquire 하고 method 가 return 할 때 lock 을 release 한다.(exception 에 의한 return 도 포함된다.)
static synchronized method 가 호출될 때는 static method 는 class 와 관계가 있기 때문에, thread 는 class와 관련된 class object 에 대한 intrinsic lock 을 acquire 한다.
그래서 class 의 static field 를 접근은 class 의 instance 의 lock 과는 다른 lock 에 의해 조정된다.
Synchronized statement
synchronized code 에서 다른 object들의 method 를 부르는 것은 아래와 같은 liveness 문제(liveness problem)를 발생시킬 여지가 있다.그러므로 이럴 때 synchronized statement 는 원하는 부분만 synchronized 할 수 있어 도움이 된다.(역자: synchronized statement block 이 하나의 atomic operation 이 되는 것이라고 여기면 될 듯 하다.)
그리고 잘 다듬어진 synchronization 을 이용해 concurrency 를 향상시키는 데 유용하다.
public class MsLunch {
private long c1 = 0;
private long c2 = 0;
private Object lock1 = new Object();
private Object lock2 = new Object();
public void inc1() {
synchronized(lock1) {
c1++;
}
}
public void inc2() {
synchronized(lock2) {
c2++;
}
}
}
에서 c1 과 c2 가 "각각"(따로) 동기화돼서 업데이트 되어야 하는 경우에 this 를 synchronized 하거나, method 에 synchronized 를 걸어서 object 를 lock 하는 방법을 선택하지 않고, lock 을 제공할 2개의 object 를 생성해서 c1과 c2 가 서로 update 할 때 영향을 주지 않도록 위와 같이 사용할 수 있다.
Liveness 정의
컨커런트 어플리케이션(concurrent application)의 적시에(in a timely manner) 실행되는 능력을 그 어플리케이션의 liveness 라고 말한다. 이 때 발생할 수 있는 문제는 아래와 같다.
- liveness 문제의 종류(liveness problem)
- deadlock
- starvation
- livelock
댓글 없음:
댓글 쓰기