Java의 세마포어는 특정 시간에 공유 리소스에 액세스할 수 있는 스레드 수를 제한하는 동기화 보조 장치입니다. 이는 java.util.concurrent 패키지의 일부이며 파일, 데이터베이스 또는 네트워크 연결과 같은 리소스에 대한 동시 액세스를 관리하는 데 사용됩니다.
세마포어는 설정된 수의 허가에 대한 액세스를 제어합니다. 각 허가는 특정 리소스에 액세스할 수 있는 권한을 나타냅니다. 세마포어는 사용 가능한 허가 수를 추적하여 동시에 리소스에 액세스할 수 있는 스레드 수를 결정합니다.
허가 : 스레드가 공유 리소스에 대한 액세스를 계속할 수 있도록 허용하는 토큰 또는 티켓입니다.
세마포어를 생성할 때 사용 가능한 허가 수를 지정합니다. 이 숫자는 동시에 리소스에 액세스할 수 있는 스레드 수를 정의합니다.
스레드가 리소스에 액세스하려면 먼저 세마포어로부터 허가를 받아야 합니다. 이는 acquire() 메서드를 사용하여 수행됩니다.
Acquire : 이 메서드는 스레드가 리소스에 액세스하려고 할 때 호출됩니다. 허가를 사용할 수 있는 경우 세마포어는 사용 가능한 허가 수를 줄이고 스레드가 계속 진행되도록 허용합니다. 사용 가능한 허가가 없으면 허가를 사용할 수 있을 때까지 스레드가 차단됩니다.
차단 동작: 사용 가능한 허가가 없으면 acquire()를 호출하는 스레드는 다른 스레드가 허가를 해제할 때까지 차단됩니다(즉, 대기합니다).
스레드가 리소스 사용을 마치면 다른 스레드에서 사용할 수 있도록 허가를 해제해야 합니다. 이는 release() 메소드를 사용하여 수행됩니다.
해제 : 이 방법은 사용 가능한 허가 수를 증가시킵니다. 허가를 기다리는 스레드가 있으면 그 중 하나가 차단 해제되고 허가를 획득할 수 있습니다.
Java에는 두 가지 유형의 세마포어가 있습니다.
세마포어 작동 방식을 더 잘 이해하기 위해 실제 구현을 살펴보겠습니다. 여러 스레드가 제한된 리소스에 액세스하려고 시도하는 간단한 시나리오를 만들어 보겠습니다.
import java.util.concurrent.Semaphore; public class SemaphoreDemo { // Creating a semaphore with 3 permits private static final Semaphore semaphore = new Semaphore(3); public static void main(String[] args) { // Creating and starting 6 threads for (int i = 1; i <= 6; i++) { new WorkerThread("Worker " + i).start(); } } static class WorkerThread extends Thread { private String name; WorkerThread(String name) { this.name = name; } @Override public void run() { try { System.out.println(name + " is trying to acquire a permit..."); // Acquiring the semaphore semaphore.acquire(); System.out.println(name + " acquired a permit."); // Simulating work by sleeping Thread.sleep(2000); System.out.println(name + " is releasing a permit."); } catch (InterruptedException e) { e.printStackTrace(); } finally { // Releasing the semaphore semaphore.release(); } } } }
이 예에서는 3개의 허가가 있는 세마포어를 생성합니다. 즉, 주어진 시간에 3개의 스레드만 코드의 중요 섹션에 액세스할 수 있습니다. 그런 다음 6개의 스레드를 생성하고 모두 허가를 얻으려고 시도합니다. 스레드가 허가를 획득하면 허가를 해제하기 전에 2초 동안 휴면하여 일부 작업을 시뮬레이션합니다.
위 코드를 실행하면 다음과 같이 출력됩니다.
Worker 1 is trying to acquire a permit... Worker 1 acquired a permit. Worker 2 is trying to acquire a permit... Worker 2 acquired a permit. Worker 3 is trying to acquire a permit... Worker 3 acquired a permit. Worker 4 is trying to acquire a permit... Worker 5 is trying to acquire a permit... Worker 6 is trying to acquire a permit... Worker 1 is releasing a permit. Worker 4 acquired a permit. Worker 2 is releasing a permit. Worker 5 acquired a permit. Worker 3 is releasing a permit. Worker 6 acquired a permit.
여기서 처음 세 스레드는 성공적으로 허가를 획득하고 작업을 시작합니다. 나머지 스레드는 허가가 해제될 때까지 기다려야 계속 진행할 수 있습니다.
세마포어는 다음과 같이 특정 리소스에 대한 동시 액세스 수를 제한해야 하는 시나리오에서 특히 유용합니다.
세마포어는 강력한 도구이지만 고유한 장점과 단점도 있습니다.
유연성: 세마포어를 사용하면 여러 스레드의 리소스 액세스를 정확하게 제어할 수 있습니다.
확장성 : 세마포어는 수많은 리소스에 대한 액세스를 쉽게 관리할 수 있습니다.
공정성 : 스레드가 공정한 방식으로 허가를 획득하도록 세마포어를 구성할 수 있습니다.
복잡성: 세마포어를 사용하면 코드가 복잡해져서 디버깅이 더 어려워질 수 있습니다.
교착 상태 : 올바르게 처리되지 않으면 세마포어는 스레드가 허가를 기다리며 무기한 차단되는 교착 상태로 이어질 수 있습니다.
일반적인 함정을 피하고 세마포어를 최대한 활용하려면 다음 모범 사례를 고려하세요.
무기한 차단하는 acquire() 대신 tryAcquire()를 사용하여 시간 제한을 두고 허가 획득을 시도할 수 있습니다. 이렇게 하면 스레드가 대기 중으로 멈추는 것을 방지할 수 있습니다.
import java.util.concurrent.Semaphore; public class SemaphoreDemo { // Creating a semaphore with 3 permits private static final Semaphore semaphore = new Semaphore(3); public static void main(String[] args) { // Creating and starting 6 threads for (int i = 1; i <= 6; i++) { new WorkerThread("Worker " + i).start(); } } static class WorkerThread extends Thread { private String name; WorkerThread(String name) { this.name = name; } @Override public void run() { try { System.out.println(name + " is trying to acquire a permit..."); // Acquiring the semaphore semaphore.acquire(); System.out.println(name + " acquired a permit."); // Simulating work by sleeping Thread.sleep(2000); System.out.println(name + " is releasing a permit."); } catch (InterruptedException e) { e.printStackTrace(); } finally { // Releasing the semaphore semaphore.release(); } } } }
리소스 누출을 방지하려면 항상 finally 블록에서 허가를 해제하세요. 이렇게 하면 예외가 발생하더라도 허가가 해제됩니다.
단일 스레드에 대한 리소스를 잠그거나 잠금 해제해야 하는 경우 바이너리 세마포어 대신 ReentrantLock 또는 동기화 사용을 고려하세요.
세마포어는 Java에서 동시성을 관리하는 강력한 도구로, 공유 리소스에 액세스하는 스레드 수를 제어할 수 있습니다. 이 기사에 설명된 기술과 모범 사례를 따르면 Java 애플리케이션에서 세마포어를 효과적으로 구현하여 안전하고 효율적인 리소스 관리를 보장할 수 있습니다.
질문이 있거나 세마포어에 대한 자신의 경험을 공유하고 싶다면 아래에 자유롭게 댓글을 남겨주세요!
에서 자세한 게시물 읽기: 세마포어를 사용하여 Java에서 동시성을 관리하는 기술
위 내용은 세마포어를 사용하여 Java에서 동시성을 관리하는 기술의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!