본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[Java] Semaphore 에 대해 알아보자.

by 돼지왕 왕돼지 2018. 12. 20.
반응형

[Java] Semaphore 에 대해 알아보자.



https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html


acquire, acquire permits, acquire timeout, acquireuninterruptibly, availablepermits, barging, binary semaphore, constructor, counting semaphore, debugging, drainpermits, fairness, FIFO, getqueuelength, hasqueuedthreads, InterruptedException, isfair, java semaphore, mutual exclusion lock, permit, release, semaphore apis, semaphore example, semaphore fairness, semaphore tutorial, Synchronization, Testing, timeout, timeunit, tryacquire, zero permit, 세마포어


-

자바 병렬 프로그래밍을 통해 학습한 내용에도 (http://aroundck.tistory.com/867) 세마포어 내용이 있지만, 이번에 실 사용하면서 semaphore 에 더 깊이 알아봐야 겠다는 생각이 들어 학습하면서 몰랐던 내용이나 중요한 것들 위주로 글을 정리해본다.





Overview


Counting Semaphore 는 특정 자원이나 특정 연산을 동시에 사용하거나 호출할 수 있는 스레드의 수를 제한하고자 할 때 사용한다.

Semaphore 클래스는 가상의 Permit 을 만들어 내부 상태를 관리하며, 클래스를 생성할 때 인자로 Permit 의 수를 넘겨주게 되어 있다.

외부 스레드는 Permit 을 요청해 확보(acquire)하거나, 이전에 확보한 Permit 을 반납(release)할 수 있다.

현재 사용할 수 있는 남은 permit이 없는 경우 (permit = 0), acquire 메소드는 남는 permit이 생기거나, 인터럽트가 걸리거나, 지정한 시간을 넘겨 타임아웃이 걸리기 전까지 대기한다.

release 메소드는 확보했던 permit 을 다시 세마포어에 반납하는 기능을 한다.





Tips


Semaphore 는 내부적으로 synchronization 을 하고 있기 때문에 밖에서 동기화를 맞춰줄 필요가 없다.


비록 constructor 를 통해 초기 permit 을 받기는 하지만, permit 수는 fix 된 것이 아니다.

release() 를 호출해주면 계속 permit 은 증가한다.


permit 이 1인 semaphore 를 binary semaphore 라고 부르며, 이른 Mutual exclusion lock 과 동일한 효과를 가진다.


constructor 는 fairness 를 param 으로 받는데, false 로 세팅되면 order 가 보장되지 않고, true 로 설정되면 order 가 보장된다. (permit 획득 order, FIFO)

timeout 이 설정되지 않은 tryAcquire 는 fairness setting 을 무시한다는 것도 꼭 알아두자.

(Note that the untimed tryAcquire methods do not honor the fairness setting, but will take any permits that are available.)





APIs


acquire() throws InterruptedException

    semaphore 의 permit 을 하나 가져간다. ( -1 시킨다 )

    permit 이 양수였을 경우에는 thread 가 계속 run 하고 그렇지 않으면 permit 을 획득할 때까지 혹은 interrupt 되기 전까지 waiting 한다.



 acquire(int permits) throws InterruptedException

    여러개의 permit 을 동시에 acquire 시도한다.

    부분이 아닌 명시한 permit 이 모두 acquire 될 때까지 혹은 interrupt 되기 전까지 waiting 한다.



acquireUninterruptibly()

acquiteUninterruptibly(int permits)

    interrupt 에 반응하지 않는 acquire



boolean tryAcquire()

boolean tryAcquire(int permits)

    이 녀석은 waiting 은 없다.

    permit 을 바로 acquire 할 수 있다면 true 를 return 하며 acquire 하고, 그렇지 않으면 false 를 하면서 acquire 하지 못한다.

    이 녀석은 fair 정책에 영향을 받지 않는다. 호출하는 순간 permit 을 획득해갈 수 있다면 waiting 하는 녀석을 신경쓰지 않고 permit 을 획득한다. 이런 것을 “barging” 이라고 부른다.


    permits 갯수를 주는 경우에는 주어진 갯수만큼 acuiqre 를 한번에 가능할 때만 acquire 하면서 true 를 return 하고, 그렇지 않으면 false


    

boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException

boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException

    TimeUnit 으로 지정한 timeout 만큼 maximum 대기를 하면서 permit acuiqre 를 시도한다.

    이 녀석은 tryAcquire 임에도 fair 정책을 따른다.

    즉 tryAcquire 를 사용하면서 fair 정책을 따르고 싶다면 tryAcquire(0, TimeUnit.SECONDS) 를 사용해야 한다.



release()

release(int permits)

    permit 을 release 한다. ( +1 을 시킨다. )

    permit 을 acquire 하려고 대기하는 thread 가 있다면 fair 정책에 따라 해당 thread 가 activate 된다.

    acquire 하지 않은 녀석이 release 해도 상관 없다.



int availablePermits()

    현재 사용 가능한 permit 갯수를 던져줌

    이 값은 대부분 debugging 이나 testing 목적으로 써야 한다. 이 값을 갖는 순간 다른 곳에서 acquire, release 가 발생하면서 값이 일치하지 않을 가능성이 높기 때문이다.



int drainPermits()

    현재 acquire 가능한 permit 을 모두 획득하고 그 수를 return 함

    즉 permit 을 0 으로 만듬



boolean isFair()

    fair 정책을 return



boolean hasQueuedThreads()

    어떤 thread 가 permit acquire 를 하기 위해 대기하고 있는지를 return

    이 녀석도 debugging, testing 용도 등으로 주로 사용해야 한다. 값을 가져간 순간에 대기자가 없어질 수도 있기 때문이다.



int getQueueLength()

    몇 개의 thread 가 permit 을 acquire 하기 위해 대기하는지 그 수를 return 한다.

    이 녀석도 debugging, testing 용도 등으로 주로 사용해야 한다. 그 수가 값을 가져간 순간 바뀌기 쉽기 때문이다.




반응형

댓글