Skip to content

Latest commit

 

History

History
66 lines (46 loc) · 2.48 KB

File metadata and controls

66 lines (46 loc) · 2.48 KB

아아템 78 공유중인 가변 데이터는 동기화해 사용하라

synchronized키워드는 해당 메서드나 블록을 한번에 한 쓰레드씩 수행하도록 보장한다. 많은 프로그래머가 동기화를 배타적 실행, 즉 한 스레드가 변경하는 중이라서 상태가 일관되지 않은 순간의 객체를 다른 스레드가 보지 못하게 막는 용도로만 사용한다

이객체에 접근하는 메서드는 그 객체에 락을 건다. 락을 건 메서드는 객체의 상태를 확인하고 필요하면 수정한다

스레드가 필드를 읽을 때 항상 수정이 완전히 반영된 값을 얻는다고 보장하지만 한 스레드가 저장한 값이 다른 스레드에게 보이는가는 보장하지 않는다 동기화는 베타적 실행뿐 아니라 스레드 사이에 안정적인 통신에 꼭 필요하다

결론: 쓰기, 읽기 메서드 모두 동기화 해야 한다

public class StopThread {

    private static boolean stopRequested;
    
    private static synchronized void requestStop() {
        stopRequested = true;
    }
    
    private static synchronized boolean stopRequested() {
        return stopRequested;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(() -> {
            int i = 0;
            while (!stopRequested()) {
                i++;
            }
        });
        backgroundThread.start();
        
        TimeUnit.SECONDS.sleep(1);
        requestStop();
    }
}

반복문에서 매번 동기화하는 비용이 크지 않지만 빠른 대안을 소개하면 volatile을 선언하면 동기화를 생략해도 된다

public class StopThread {
    
    private static volatile boolean stopRequested;
    
    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(() -> {
            int i = 0;

            while (!stopRequested) {
                i++;
            }
        });
        
        backgroundThread.start();
        stopRequested = true;
    }
}

volatile 한정자는 베타적 수행과는 상관없지만 항상 가장 최근에 기록된 값을 읽게 됨을 보장한다

하지만 제대로 쓰기 어렵다

그냥 가장 좋은 방법은 애초에 가변 데이터를 공유하지 않는 것이다 불변 데이터만 공유하거나 아무것도 공유하지말자 다시말해 가변 데이터는 단일 쓰레드에서만 사용하도록 하자