Java는 멀티 스레드 프로그래밍에서의 동기화 문제에 대해 3가지 방법을 제시한다.

  1. synchronized 키워드
  2. volatile 변수
  3. Atomic 클래스

 

이 세가지 중에서 synchronized 키워드에 대해 정리해보자.

 

 

 

synchronized 키워드


Java에서 synchronized 키워드를 활용하는 방법은 두 가지다.

  1. synchronized 메서드 ( 메서드 자체에 해당 키워드를 적용 )
  2. synchronized 블럭 ( 메서드 내부에 동기화가 필요한 로직에만 synchronized 블럭으로 감싸는 형태 ) 

 

먼저 메서드 자체에 synchronized 키워드를 붙여줬을 때.

public class DemoSynchronization {

    private String mMessage;
    
    public static void main(String[] args) {
        DemoSynchronization myInstance = new DemoSynchronization();
        
        new Thread(() -> {
            for (int i = 0; i < 1000; ++i) {
                myInstance.printMessage("thread_1");
            }
        }).start();
        
        new Thread(() -> {
            for (int i = 0; i < 1000; ++i) {
                myInstance.printMessage("thread_2");
            }
        }).start();
    }
    
    public synchronized void printMessage(String message) {
        mMessage = message;
        
        try {
            Thread.sleep( Math.random() * 100 );
        } catch (InterruptedException e) {
        
        }
        
        if (false == mMessage.equals(message)) {
            System.out.println("타 스레드에 의해 mMessage 변수값이 변경됨");
        }
    }
}

 

두 스레드가 각각 myInstance 인스턴스의 printMessage() 메서드를 호출한다.

두 스레드가 printMessage() 메서드를 호출하지만, 동기화 메서드이기 때문에 동시에 실행할 수 없게 된다. ( 동기화 보장 )

여기서 생각해봐야할 점은 어떤 방법으로 동시에 실행할 수 없게 하는걸까? 이다.

한 스레드가 printMessage() 동기화 메서드를 실행하면서 lock을 건다.

여기서 중요한 점은 메서드 자체에만 lock을 거는 것이 아닌, 해당 동기화 메서드를 호출한 객체 자체에 lock을 건다는 것

 

그럼 synchronized를 메서드 내부에서 블럭 형태로 사용했을 경우를 살펴보자.

메서드 내부의 특정 로직에 대해서만 동기화를 적용해줄 수 있다.

public class DemoSynchronization {

    private ArraryList<Integer> mList = new ArrayList<>();

    public static void main(String[] args) {
        DemoSynchronization myInstance = new DemoSynchronization();
        
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10000; ++i) {
                myInstance.add(i);
            }
        });
        
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10000; ++i) {
                myInstance.add(i);
            }
        });
        
        t1.start(); t2.start();
        t1.join(); t2.join();
    }
    
    public void add(int x) {
    
        // 이 부분에는 동기화가 필요없는 로직을 넣는다.
    
        synchronized (this) {
            if (false == mList.contains(x)) {
                mList.add(x);
            }
        }
    }
}

 

'Programming > Java' 카테고리의 다른 글

[Java] Atomic Type  (0) 2020.04.13
[Java] volatile 키워드  (0) 2020.04.13
[Java] @ 어노테이션  (0) 2020.03.31
[Java] Optional<T> 클래스  (0) 2020.03.24
[Java ] 함수형 인터페이스 ( Functional Interface )  (0) 2020.03.24