ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java - Mutex & Semaphore & Monitor
    Language/Java 2022. 4. 6. 17:17

    뮤텍스(Mutex Exclusion)

    뮤텍스란?

    멀티프로그래밍 환경에서 자원에 대한 접근에 제한을 강제하기 위한 동기화 기법이다. 뮤텍스의 특징은 아래와 같다.

     

    1. boolean 타입의 lock 변수를 사용하기 때문에, 1개의 공유 자원에 대한 접근을 제한한다.

    2. 공유 자원을 사용 중인 스레드가 있을 때, 다른 스레드가 공유 자원에 접근한다면 블로킹 후 대기 큐로 보낸다.

    3. lock을 건 스레드만 lock을 해제할 수 있다.


    세마포어(Semaphore)

    세마포어란?

    멀티프로그래밍 환경에서 다수의 프로세스나 스레드가 n개의 공유 자원에 대한 접근을 제한하는 방법으로 사용되는 동기화 기법이다. 세마포어의 특징은 아래와 같다.

     

    1. 세마포어 변수를 통해 wait, signal을 관리한다. 세마포어 변수는 0 이상의 정수형 변수를 갖는다.

    2. n개의 공유 자원에 대한 접근을 제한할 수 있으며, 이를 계수 세마포어라고 한다.

    3. 접근 가능한 공유 자원의 수가 1개일 때는 이진 세마포어로 뮤텍스와 유사하게 사용할 수 있다.

    4. 큐에 연결된 스레드를 깨우는 방식에 따라 강성 세마포어(FIFO 정책을 사용하여 스레드를 깨움)와 약성 세마포어(특별한 순서를 명시하지 않고 스레드를 깨움)로 구분된다.

    5. 세마포어는 signaling 메커니즘을 사용하기 때문에, lock을 걸지 않은 스레드도 signal을 보내 lock을 해제할 수 있다.

     

    세마포어를 사용한 동시 접근 제어
    class Resource {
        private final Semaphore semaphore;
        private final int maxThread;
    
        public Resource(int maxThread) {
            this.maxThread = maxThread;
            this.semaphore = new Semaphore(maxThread);
        }
    
        public void use() {
            try {
                semaphore.acquire();
                System.out.println("[" + Thread.currentThread().getName() + "]" + (maxThread - semaphore.availablePermits())
                        + "개의 스레드가 점유중");
                Thread.sleep(1000);
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    synchronized의 경우 오직 하나의 스레드만 수행 가능했다면, 세마포어는 동시에 실행할 수 있는 스레드의 수를 제어할 수 있다. 위 코드는 동시에 수행 중인 스레드의 번호를 출력하는 코드이다.

     

    public class Main {
        public static void main(String[] args) throws Exception {
            Resource resource = new Resource(3);
    
            for (int i = 1; i <= 10; i++) {
                Thread t = new Thread(resource::use);
                t.start();
            }
        }
    }

    Resource 인스턴스의 use( ) 메서드를 maxThread 수만큼 스레드가 동시에 호출 가능하도록 만들었다. use( ) 메서드를 호출하면 세마포어를 몇 개의 스레드가 점유 중인지 출력하고, 1초간 sleep을 호출한다. 실제로 스레스를 생성해서 동기화가 잘 지켜지는지 실행해보도록 하겠다.

     

    [Thread-0] 현재 3개의 스레드가 점유중
    [Thread-1] 현재 3개의 스레드가 점유중
    [Thread-2] 현재 3개의 스레드가 점유중
    [Thread-3] 현재 1개의 스레드가 점유중
    [Thread-5] 현재 3개의 스레드가 점유중
    [Thread-4] 현재 2개의 스레드가 점유중
    [Thread-6] 현재 2개의 스레드가 점유중
    [Thread-8] 현재 3개의 스레드가 점유중
    [Thread-7] 현재 2개의 스레드가 점유중
    [Thread-9] 현재 1개의 스레드가 점유중

    실행결과는 위와 같다. maxThread에서 설정한 최대 스레드 수인 3개 이하로만 세마포어를 점유하는 것을 확인할 수 있다. 이렇게 세마포어를 사용하여 동시에 수행되는 스레드의 수를 제어하는 것이 가능하다.

    추가로, Java에는 뮤텍스 라이브러리가 없기 때문에, 이진 세마포어를 사용해서 구현해야 한다.


    모니터(Monitor)

    모니터란?

    뮤텍스와 세마포어는 상호 배제를 위한 동기화 개념이다. 그러나 완벽한 상호 배제를 제공한다고 할 수 없기 때문에, 이를 보완한 모니터를 이용하면 훨씬 쉽게 동기화를 사용할 수 있다.

    세마포어는 wait & signal의 연산 순서를 바꿔서 실행하거나 둘 중 하나라도 생략하면 상호 배제를 위반하는 상황이어서 교착 상태가 발생한다. 또한, wait & signal 연산이 프로그램 전체에 구성되어 있으면 세마포어의 영향이 미치는 곳이 어딘지 파악하기 어렵기 때문에, 세마포어를 사용해서 프로그램을 구현하는 것은 매우 어려운 일이다. 

    이러한 단점들을 극복하기 위해 모니터가 등장했고, 이는 프로그래밍 언어 수준에서 제공된다.

     

    모니터의 원리

     

    모니터는 임계 구역을 지켜내기 위한 방법인 상호 배제를 프로그램으로 구현한 것이며, 이진 세마포어만 가능하다. 위 사진은 모니터의 구조를 그림으로 나타낸 것이다.

     

    모니터는 공유 자원, 공유 자원 접근 함수로 이루어져 있고, 2개의 큐를 가지고 있다.

     

    상호 배타 큐(Mutual Exclusion Queue)

    ㆍ 공유 자원에 하나의 프로세스만 진입하도록 하기 위한 큐이다. 공유 자원을 사용하는 스레드가 존재한다면 상호 배타 큐에 존재한다.

     

    조건 동기 큐(Conditional Synchronization Queue)

    ㆍ 공유 자원의 lock이 해제되기를 기다리는 스레드가 대기하는 큐이다.

     

     

    위 사진은 모니터를 통해 프로세스가 자원에 접근하는 방식을 표현한 것이다. 공유 자원을 점유 중인 프로세스(스레드)는 lock을 가지고 있다. 공유 자원을 점유 중인 프로세스(스레드)가 있는 상황에서 다른 프로세스(스레드)가 공유 자원에 접근하려고 하면 외부 모니터 조건 동기 큐에서 진입을 기다린다.


    출처

    https://steady-coding.tistory.com/557

     

    728x90

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

    Java - '==' 연산자 와 'equals()'를 이용한 문자열 비교  (0) 2022.09.20
    Java - Wrapper Class  (0) 2022.09.20
    Java - Reflection  (0) 2022.04.05
    Java - hashCode() & equals()  (0) 2022.04.05
    Java - Thread  (0) 2022.03.28

    댓글

Designed by Tistory.