읽어보면 좋을 것 같은 github
https://github.com/benelog/java-concurrency
위 깃헙에서 예제 코드들을 잘 만들어 놓은 것 같고 이해하는데 좋아서 링크를 삽입해놓았습니다.
자바에서는 모든 객체가 모니터를 가지고 있습니다. 이는 공유 자원에 대해서 상호 충돌 문제를 해결하기위해서 만들어진 것입니다. 하지만 이러한 모니터를 우리는 직접적으로 호출해서 사용하지는 않고 간접적으로 사용하게 됩니다. 이때 사용하는 것이 Syncronized 키워드 입니다. 우리말로 “동기”라고 하는데 자바에서는 보통 비동기보다는 동기를 더 많이 보시게 됩니다.
한개의 공유자원이 있다고 생각합시다. 이 공유자원을 한사람만 사용하면 그다지 문제가 일어나지 않습니다. 그저 원할 때 사용하고 안하고를 결정할 수 있기 때문이죠. 문제는 2개 이상의 사람이 같이 사용하게 되면 일어납니다. 여러 사람이 동시에 공유자원을 사용하려고 하면 race condition이라고 해서 서로 사용하려고 경쟁하는 현상이 일어날 수 있고, 가장 큰 문제는 “**공유자원을 사용하고 나서 나온 결과를 예측할 수 없다”**라는 점입니다. 결과를 예측 할 수 없다는 것은 개발자에게 있어서 그다지 좋은 상황이 아니고 의도적이지 그런 결과를 만들어낸 것이 아니기 때문에 일어나서는 안됩니다. 이때 Syncronized 키워드를 사용하면 한번에 한 사람만이 공유자원에 접근하도록 만들어 줍니다.
실제 코드를 통해서 살펴보도록 합시다.
public class Node {
private int amount;
public Node(int amount){
this.amount = amount;
}
public void add(int num){
amount += num;
}
public void sub(int num){
amount -= num;
}
}
위와 같은 노드가 있다고 합시다.
해당 노드는 단일 쓰레드에서는 그 어떠한 작동을 하여도 문제가 그다지 발생하지 않습니다.
왜냐하면 단일 코드에서는 절차를 생각하면서 코드를 만들게 되면 생각한대로 움직여주기 때문입니다.
하지만 멀티쓰레드를 사용하는 코드를 보도록 합시다.
@Test
void 동기_예제1() throws InterruptedException {
Node node = new Node(1000);
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
node.add(1);
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
node.sub(1);
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(node.getAmount());
}
result