임계 영역
이라고 합니다.상호배제
(각 스레드는 공유 자원의 손상을 방지하기 위해 배타적으로(독점적으로) 공유 자원을 사용해야 함) 되어야 합니다.race condition
문제가 발생할 수 있습니다.세마포어는 동시에 임계 영역에 접근 가능한 스레드 수를 정해, 그 수만큼 스레드가 동시에 임계 영역에 접근할 수 있도록 합니다.
각 스레드들은 임계영역에 접근할때 카운트 값을 1 감소시키고 임계영역에서 빠져나올때 카운트값을 1 증가시킵니다.
세마포어를 java 코드로 작성해보면 아래와 같습니다.
public class Semaphore{
int count; //동시에 임계영역에 접근할 수 있는 스레드 수
public Semaphore(int count){
this.count = count;
}
public synchronized void Wait(int index){
//lock
count--;
if(count < 0) //이 객체의 대기큐에서 기다림
System.out.println(index + " 스레드 현재 큐에서 대기중");
this.wait();
} //unlock
public synchronized void Signal(int index){
//lock
count++;
if(count <= 0) // 기다리는 스레드가 있음
this.notify(); // 대기큐에서 대기중인 스레드 중 하나를 깨움
System.out.println(index + " 스레드가 대기큐에서 스레드 깨움");
} //unlock
참고로 java에서는 모든 객체가 대기 큐를 가지고 있으며, 각 객체에 대해 wait(), notify(), notifyAll() 멤버 함수를 사용할 수 있습니다.
wait()를 호출하여 대기 상태가 되면 synchronized에 의해 획득한 lock은 자동으로 풀리고, 나중에 nofity() 의해 깨어나면 자동으로 다시 lock을 획득합니다.
위의 코드를 테스트 해보기 위해 main클래스를 작성합니다.
public class Main{
public static void main(String[] args) throws Exception{
Semaphore semaphore = new Semaphore(1);
new Thread(() -> {
try {
Thread.sleep(1000);
semaphore.Wait(1);
Thread.sleep(1000);
semaphore.Signal(1);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
Thread.sleep(1000);
semaphore.Wait(2);
Thread.sleep(1000);
semaphore.Signal(2);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
테스트를 위해서 sleep()을 중간 중간 호출합니다.
어떤 스레드가 먼저 실행되냐에 따라 대기 큐에 들어가는 스레드가 바뀔 수 있습니다.
https://junghyun100.github.io/Semaphore&Mutex/
https://mangkyu.tistory.com/104
https://velog.io/@logandev/%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4%EC%99%80-%EB%AE%A4%ED%85%8D%EC%8A%A4-%EC%B0%A8%EC%9D%B4
https://worthpreading.tistory.com/90