ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 동기화 synchronized
    language/JAVA 2019. 1. 30. 17:38
    반응형

    그런데 두 개 이상의 스레드가 객체에 있는 하나의 데이터에 접근할 때 문제가 발생할 수 있습니다. (병행성문제)


    위 코드를 보면 Runnable이 구현된 Banker 클래스에서 BankAccount 객체에 잔고가 0보다 클 때만 withdraw 메소드를 호출합니다.


    하지만 메인 메소드에서 오른쪽과 같은 코드를 구현하고 나면 잔고는 -100이 됩니다.


    두 스레드에서 모두 같은 BankAccount 인스턴스에 접근하고 있기 때문에 생긴 문제입니다. one 스레드에서 잔고를 확인후 sleep 메소드가 호출되어 대기상태가 되기 때문에 잔고가 변하지 않았습니다. two 스레드 역시 잔고를 확인하는 시점에서는 잔고가 100이기 때문에 결국 withdraw 메소드가 두 번 실행되어 잔고가 -100이 된 것입니다.


    이 문제를 해결하기 위해서는 makeWithdrawal() 메소드가 원자적으로 작동해야 합니다. 즉, makeWithdrawal() 메소드가 실행되고 나면 다른 스레드가 끼어들기 전에 메소드가 종료 되어야 합니다.


    synchronized 라는 키워드를 사용하게 되면 이 문제를 해결할 수 있습니다. synchronized 키워드를 붙인 메소드는 한 번에 한 스레드만 접근이 가능합니다.


    이렇게 동기화 된 메소드가 있으면 객체에 락을 이용할 수 있습니다. 그 객체의 락에 맞는 열쇠를 가지고 있는 스레드만 동기화된 메소드에 들어갈 수 있게 되는 것입니다.


    락은 메소드마다 하나씩 있는 것이 아니고 객체마다 하나씩 있습니다. 객체에 동기화된 메소드가 두 개 있다고 해서 같은 메소드에 스레드 두 개가 들어갈 수 있는 것은 아닙니다. 즉 동기화된 메소드 하나에 스레드 두 개가 들어갈 수는 없습니다.


    객체의 인스턴스 변수를 조작할 가능성이 있는 메소드가 여러 개 있다면 그런 메소드는 모두 synchronized 메소드로 보호해야 합니다. 동기화의 목적은 중요한 데이터를 보호하는 데 있습니다. 하지만 데이터 자체를 잠그는 것이 아니라 그 데이터를 접근하는 메소드를 동기화 시켜야 합니다.


    그렇다면 어떤 스레드가 콜 스택을 쌓아 올리다가 갑자기 동기화된 메소드를 만나면 어떤 일이 일어날까요? 스레드에서는 메소드에 들어가려면 열쇠가 필요하다는 것을 깨닫게 됩니다. 그리고는 열쇠를 찾겠죠. 만약, 열쇠를 쓸 수 있으면 스레드에서는 열쇠를 얼른 집어 넣어서 메소드로 들어갑니다.


    동기화도니 메소드가 끝나기 전에는 절대 열쇠를 내주지 않지요. 그 스레드가 열쇠를 잡고 있는 동안에는 다른 어떤 스레드도 그 객체의 동기화된 메소드에 들어갈 수가 없습니다. 그 객체에 대한 열쇠가 없으니까요.


    synchronized 블록을 사용해서 조금 더 정교한 동기화가 가능합니다.



    동기화된 코드를 사용할 때는 스레드의 교착상태에 각별한 주의를 기울여야 합니다. 스레드 교착상태는 스레드 두 개가 서로 상대방이 필요로 하는 열쇠를 가지고 있는 경우 생길 수 있습니다. 이렇게 되면 절대로 그 상황에서 벗어날 수가 없기 때문에 그 두 스레드는 마냥 기다리기만 합니다.


    자바에서는 이런 교착상태를 처리할 수 있는 매커니즘이 없습니다. 아예 교착상태에 빠졌다는 사실을 인식하지도 못합니다. 따라서 개발자의 각별한 유의가 필요 합니다.


    반응형

    'language > JAVA' 카테고리의 다른 글

    Collection  (0) 2019.01.30
    제네릭, Generic  (0) 2019.01.30
    스레드 Thread  (0) 2019.01.30
    네트워크, 소켓  (0) 2019.01.30
    serialization(직렬화)  (0) 2019.01.23
Designed by Tistory.