JavaRush /Java Blog /Random-KO /Java의 동기식 큐 예제 - 문제 해결 생산자 소비자
profeg
레벨 18

Java의 동기식 큐 예제 - 문제 해결 생산자 소비자

Random-KO 그룹에 게시되었습니다
Java의 동기식 큐 예제 - 문제 해결 생산자 소비자
동기 대기열은 각 삽입 작업이 다른 스레드에서 해당 제거 명령을 기다려야 하며 그 반대의 경우도 마찬가지인 특별한 유형의 BlockingQueue입니다. 동기 대기열에서 put() 메서드를 호출하면 다른 스레드가 해당 요소를 가져올 때까지 차단됩니다. 따라서 다른 스레드가 요소를 제거하려고 시도했지만 해당 요소가 없으면 해당 스레드 는 다른 스레드가 해당 요소를 대기열에 넣을 때까지 차단됩니다 . 동기식 대기열은 올림픽 성화를 들고 달리는 운동선수( 스레드 ) 로 생각할 수 있습니다 . 그는 성화(전달되는 개체)를 들고 달리며 반대편에서 기다리고 있는 다른 선수에게 전달합니다. 이름에 주의를 기울이면 동기식으로 데이터를 다른 스레드로 전송하는 동기식 대기열이라는 이름이 붙었다는 것을 알 수 있습니다 . 단순히 데이터를 넣고 종료하는 대신 누군가가 데이터를 가져오기를 기다립니다(비동기 작업). CSP와 Ada에 익숙하다면 동기화된 대기열이 스레드 회의와 유사하다는 것을 알고 있을 것입니다. 이는 한 스레드에서 실행 중인 개체가 일부 정보, 이벤트 또는 작업을 전달하기 위해 다른 스레드의 개체와 동기화해야 하는 제어 전송 구성에 매우 적합합니다. 이전 다중 스레드 프로그래밍 튜토리얼에서는 wait 및 informBlockingQueue 메소드를 사용하여 생산자-소비자 문제를 해결하는 방법을 배웠습니다 . 이제 동기식 대기열을 사용하여 생산자-소비자 패턴을 적용하는 방법을 알아 보겠습니다 . 이 클래스는 생산자 및 소비자 스레드의 대기 순서를 지정하기 위한 공정한 동작을 추가로 지원합니다. 기본적으로 이 순서는 보장되지 않습니다. 그러나 공정한 속성으로 생성된 대기열은 FIFO (Firs In First Out) 대기열의 스레드에 대한 액세스를 보장합니다.
Java에서 동기식 대기열을 사용하는 생산자/소비자.
Java의 동기식 큐 예제 - 문제 해결 생산자 소비자 - 1 위에서 말했듯 이 모든 프로그래밍 언어에서 스레드 간 통신을 이해하는 데 생산자-소비자 문제보다 더 좋은 것은 없습니다 . 이 문제에서 한 스레드는 이벤트와 작업을 생성하는 생산자 역할을 하고 다른 스레드는 이벤트 및 작업 소비자 역할을 합니다. 공유 버퍼는 생산자에서 소비자로 데이터를 전송하는 데 사용됩니다. 이 문제를 해결하기 어려운 경우는 극단적인 경우입니다. 예를 들어 제조사가 다음과 같은 이유로 기다려야 하는 경우가 있습니다. 버퍼가 가득 찼거나 소비자가 기다려야 하는 이유는 다음과 같습니다. 버퍼가 비어 있습니다. 이 문제는 쉽게 해결되었기 때문에... 블로킹 큐는 데이터를 저장하는 버퍼뿐만 아니라 흐름 제어도 제공하여 버퍼가 가득 차면 put() 메서드를 호출하는 스레드(생산자)를 차단하고, 버퍼가 가득 차면 take() 메서드를 호출하는 스레드(소비자)를 차단합니다. 버퍼가 비어 있었습니다. 이제 용량이 0인 특별한 종류의 병렬 컬렉션 인 동기식 대기열을 사용하여 이와 동일한 문제를 해결하겠습니다 . 다음 예에는 PRODUCERCONSUMER 라는 두 개의 스레드가 있습니다 .(항상 스레드에 이름을 지정합니다. 이는 멀티 스레드 프로그래밍의 매우 좋은 스타일입니다.) 첫 번째 스레드는 게임에 점수를 게시하고 두 번째 스레드는 이를 소비합니다. 게임의 점수는 String 유형의 객체에 지나지 않습니다. 그러나 다른 유형으로 프로그램을 실행하면 아무런 차이가 없습니다. 동기식 대기열의 작동 방식과 생산자-소비자 문제를 해결하는 방법을 이해하려면 다음을 수행해야 합니다. Eclipse 환경에서 디버깅(디버그)을 위한 프로그램을 실행하거나 단순히 Consumer.start()를 주석 처리하여 생산자 스레드를 시작합니다. 소비자 스레드가 실행 중이 아니면 생산자 스레드는 queue.put(event)에서 차단됩니다. 실행 중인 경우 프로듀서 [PRODUCER]가 :FOUR 이벤트를 게시하는 것을 볼 수 없습니다. 이런 일이 일어나는 이유는 다른 스레드가 데이터를 가져올 때까지 스레드 게시 데이터가 차단되고 그 반대의 경우도 가능하도록 보장하는 동기식 대기열의 특정 동작입니다. producer.start()를 주석 처리하여 나머지 코드를 테스트할 수 있습니다. 소비자 스레드만 시작합니다. 프로그램이 출력하는 내용을 주의 깊게 살펴보면 출력 순서가 반대라는 것을 알 수 있습니다. [PRODUCER] 스레드가 데이터 를 생성하기 전에 [CONSUMER] 스레드가 데이터를 가져온 것 같습니다 . 이는 동기 대기열이 기본적으로 대기열을 보장하지 않기 때문입니다. 그러나 FIFO 순서로 스레드에 대한 액세스를 설정하는 공정성 규칙이 있습니다. 다음과 같이 오버 로드된 동기식 대기열 생성자 에 true를 전달하여 이러한 규칙을 활성화할 수 있습니다 . import java.util.concurrent.SynchronousQueue; /** * Java Program to solve Producer Consumer problem using SynchronousQueue. A * call to put() will block until there is a corresponding thread to take() that * element. * * @author Javin Paul */ public class SynchronousQueueDemo{ public static void main(String args[]) { final SynchronousQueue queue = new SynchronousQueue (); Thread producer = new Thread("PRODUCER") { public void run() { String event = "FOUR"; try { queue.put(event); // thread will block here System.out.printf("[%s] published event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; producer.start(); // starting publisher thread Thread consumer = new Thread("CONSUMER") { public void run() { try { String event = queue.take(); // thread will block here System.out.printf("[%s] consumed event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; consumer.start(); // starting consumer thread } } Output: [CONSUMER] consumed event : FOUR [PRODUCER] published event : FOUR new SynchronousQueue(boolean fair).
Java의 동기 대기열에 대해 기억해야 할 사항입니다.

다음은 Java에서 이 특별한 유형의 차단 대기열의 몇 가지 중요한 속성입니다. 동기화된 방식으로 한 스레드에서 다른 스레드로 데이터를 전달하는 것은 매우 유용합니다. 이 대기열에는 용량이 없으며 다른 스레드가 이를 해제할 때까지 차단됩니다.

  1. 동기식 대기열이 차단되고 한 스레드가 데이터를 가져올 준비가 될 때까지 다른 스레드가 데이터를 넣으려고 시도합니다.
  2. 동기 대기열에는 볼륨이 없습니다. 즉, 데이터가 포함되어 있지 않습니다.
  3. 동기식 대기열은 스레드가 대기 중인 스레드에 제어를 전달하거나 허용되는 경우 새 스레드를 생성하는 정방향 대기열 전략을 구현하는 데 사용됩니다. 그렇지 않으면 제어가 전송되지 않습니다.
  4. 이 큐는 널 데이터를 허용하지 않습니다. null 요소를 추가하려고 하면 NullPointerException이 발생합니다 .
  5. 컬렉션의 다른 메서드(예: 포함)를 사용하는 경우 동기식 큐는 빈 컬렉션처럼 동작합니다.
  6. 요소를 제거하려고 할 때만 요소가 존재하기 때문에 동기식 큐의 peek 메소드를 사용할 수 없습니다. 또한 다른 스레드가 요소를 제거하려고 시도할 때까지는 어떤 방법을 사용하여 요소를 삽입할 수 없습니다.
  7. 다음과 같은 이유로 동기 대기열에 반복자를 사용할 수 없습니다. 요소가 없습니다.
  8. 동기식 대기열은 스레드에 대한 액세스가 FIFO 순서로 보장되는 공정한 규칙을 사용하여 생성될 수 있습니다.
아마도 이것은 Java의 동기 대기열에 관한 것입니다 . 우리는 이 다중 스레드 컬렉션의 몇 가지 특별한 기능을 살펴보고 Java의 동기식 대기열을 사용하여 고전적인 생산자-소비자 문제를 해결하는 방법을 배웠습니다. 그건 그렇고, 그것을 대기열이라고 부르는 것은 완전히 정확하지 않습니다. 왜냐하면... 요소가 포함되어 있지 않습니다. put()에 대한 호출은 다른 스레드가 take()를 호출할 때까지 완료되지 않습니다. 객체를 공유하는 스레드의 만남의 장소로 생각하는 것이 더 정확합니다. 즉, 이는 Java에서 객체의 동기화된 전달을 위한 유틸리티이며 아마도 wait 및 inform 메소드에 대한 더 안전한 대안일 것입니다 .
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION