병렬 프로그램이 단순히 스레드와 lock만 신경써서 될 일은 아니라고 함
멀티 스레드에 안전한 코드는 변경 가능한 공유 상태에 대한 접근을 관리하는 것.
(shared, mutable data)
스레드 안전성은 데이터에 제어없이 동시에 접근하는 걸 막으려는 의미라고 함.
키워드는 멀티스레드, 공유된 상태, 단일 연산 정도로 볼 수 있을듯.
@ThreadSafe
public class StatelessServlet implements Servlet{
public void service(ServletRequest req, ServletResponse res){
...
}
}
@NotThreadSafe
public class UnsafeCountingServlet implements Servlet{
private long count;
public void service(ServletRequest req, ServletResponse res){
...
count++;
...
}
}
위 코드는 thread safe하지 않다는데... 흠.......
나도 비슷한 상황을 겪었는데 그 때 상황은
JPA 엔티티에 count 변수가 있었고, count 변수값을 변경하는 메서드를 따로 동기화 해주지는 않았음.
그 때랑 이 코드는 다른 상황인가..?
이 코드는 여러 스레드가 확실히 동시에 접근할 수 있음.
근데 JPA 엔티티의 count 필드 변경 함수는 1개의 http request에 의해 실행되는 것.
그래서 여러 스레드가 접근하거나 하지는 않는듯. 다른 상황이네.
단일 연산 변수(AtomicInteger, AtomicReference<> 같은거)로는 여러 상태값의 동기화를 보장하지 못해서 lock으로 단일 연산으로 만들어줘야 함.
여러 동작을 단일 연산으로 만드는거니까 트랜잭션의 atomic한 성질이랑 좀 비슷한 느낌이네.
암묵적인 락(모니터 락)
자바는 synchronized 구문으로 락을 제공.
스레드가 synchronized 블록에 들어가기 전에 자동으로 확보되며, 해당 블록을 벗어날 때 해제됨.
상호배제 방식(mutual exclusive)으로 동작한다고 함.
reentrant(재진입성)
암묵적인 락은 재진입 가능하다고 함. (이미 락을 획득한 스레드가 다시 락을 확보할 수 있는거라고 함...)
부모 클래스의 메서드를 오버라이드하고 두 메서드에 모두 synchronized가 붙어있을 때,
재진입성이 없으면 데드락에 빠진다고 함..
락은 공유된 상태에 여러 스레드가 순차적으로 접근하도록 해서 일관된 상태를 유지할 수 있도록 해줌.
하나의 락으로 동기화해야 한다?
용어
synchronized 블록의 범위를 줄이면 스레드 안전성을 유지하면서 쉽게 동시성(성능)을 향상 가능.
락을 얻고 해제하는 것도 부하가 꽤 된다고 함.
그래서 synchronized 블록을 너무 잘게 쪼개는 것도 좋지 않다고 함...