Java에서 스레드로부터 안전한 BlockingQueue란 무엇입니까? 언제 사용해야합니까? 구현 첨부
게시 됨: 2021-04-30
지금까지 Crunchify에서 생산자 소비자 개념에 대한 두 개의 기사를 작성했습니다. 첫 번째는 Java Semaphore 및 Mutex에 대해 설명하고 두 번째는 동시 읽기/쓰기에 대해 설명합니다.
이 Java Tutorial에서는 동일한 생산자/소비자 개념을 살펴보고 BlockingQueue in Java
를 설명합니다.
Java에서 Blocking Queue의 장점은 무엇입니까?
java.util.Queue
는 요소를 검색할 때 대기열이 비어 있지 않을 때까지 대기하고 요소를 저장할 때 대기열에서 공간을 사용할 수 있을 때까지 기다리는 작업을 지원합니다.

4개의 Java 클래스를 생성해야 합니다.
- 메시지를 넣고 가져오는 CrunchifyMessage.java
- 큐에 메시지를 넣는 CrunchifyBlockingProducer.java
- 큐에서 메시지를 가져오는 CrunchifyBlockingConsumer.java
- 테스트 시작을 위한 CrunchifyBlockingMain.java
BlockingQueue 구현은 thread-safe
합니다. 모든 대기열 방법은 본질적으로 원자적이며 내부 잠금을 사용합니다.
Java에서 Thread-Safe BlockingQueue 구현을 시작하겠습니다.
1 단계
CrunchifyMessage.java
클래스를 생성합니다. 이것은 간단한 Java 객체입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com . crunchify . example ; /** * @author Crunchify.com * simple Message class to put and get message into queue */ public class CrunchifyMessage { private String crunchifyMsg ; public CrunchifyMessage ( String string ) { this . crunchifyMsg = string ; } public String getMsg ( ) { return crunchifyMsg ; } } |
2 단계
간단한 msg를 생성한 생산자 CrunchifyBlockingProducer.java
를 생성하고 큐에 넣습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package com . crunchify . example ; import java . util . concurrent . BlockingQueue ; /** * @author Crunchify.com * */ public class CrunchifyBlockingProducer implements Runnable { private BlockingQueue <CrunchifyMessage> crunchQueue ; public CrunchifyBlockingProducer ( BlockingQueue <CrunchifyMessage> queue ) { this . crunchQueue = queue ; } @Override public void run ( ) { // producing CrunchifyMessage messages for ( int i = 1 ; i < = 5 ; i ++ ) { CrunchifyMessage msg = new CrunchifyMessage ( "i'm msg " + i ) ; try { Thread . sleep ( 10 ) ; crunchQueue . put ( msg ) ; System . out . println ( "CrunchifyBlockingProducer: Message - " + msg . getMsg ( ) + " produced." ) ; } catch ( Exception e ) { System . out . println ( "Exception:" + e ) ; } } // adding exit message CrunchifyMessage msg = new CrunchifyMessage ( "All done from Producer side. Produced 50 CrunchifyMessages" ) ; try { crunchQueue . put ( msg ) ; System . out . println ( "CrunchifyBlockingProducer: Exit Message - " + msg . getMsg ( ) ) ; } catch ( Exception e ) { System . out . println ( "Exception:" + e ) ; } } } |
3단계
큐에서 메시지를 소비하는 클래스 CrunchifyBlockingConsumer.java
를 만듭니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com . crunchify . example ; import java . util . concurrent . BlockingQueue ; /** * @author Crunchify.com * */ public class CrunchifyBlockingConsumer implements Runnable { private BlockingQueue <CrunchifyMessage> queue ; public CrunchifyBlockingConsumer ( BlockingQueue <CrunchifyMessage> queue ) { this . queue = queue ; } @Override public void run ( ) { try { CrunchifyMessage msg ; // consuming messages until exit message is received while ( ( msg = queue . take ( ) ) . getMsg ( ) ! = "exit" ) { Thread . sleep ( 10 ) ; System . out . println ( "CrunchifyBlockingConsumer: Message - " + msg . getMsg ( ) + " consumed." ) ; } } catch ( InterruptedException e ) { e . printStackTrace ( ) ; } } } |
4단계
BlockingQueue 테스트를 실행하는 간단한 CrunchifyBlockingMain.java
메서드를 만듭니다. 이 프로그램을 실행하여 BlockingQueue 동작을 확인하십시오.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package com . crunchify . example ; import java . util . concurrent . ArrayBlockingQueue ; import java . util . concurrent . BlockingQueue ; /** * @author Crunchify.com * */ public class CrunchifyBlockingMain { public static void main ( String [ ] args ) { // Creating BlockingQueue of size 10 // BlockingQueue supports operations that wait for the queue to become non-empty when retrieving an element, and // wait for space to become available in the queue when storing an element. BlockingQueue <CrunchifyMessage> crunchQueue = new ArrayBlockingQueue < > ( 10 ) ; CrunchifyBlockingProducer crunchProducer = new CrunchifyBlockingProducer ( crunchQueue ) ; CrunchifyBlockingConsumer crunchConsumer = new CrunchifyBlockingConsumer ( crunchQueue ) ; // starting producer to produce messages in queue new Thread ( crunchProducer ) . start ( ) ; // starting consumer to consume messages from queue new Thread ( crunchConsumer ) . start ( ) ; System . out . println ( "Let's get started. Producer / Consumer Test Started.\n" ) ; } } |
BlockingQueue 는 null 요소를 허용하지 않습니다. 구현에서는 null 을 추가 , 넣거나 제공 하려는 시도에서 NullPointerException 이 발생합니다.
null 은 폴 작업의 실패를 나타내는 센티넬 값으로 사용됩니다.
결과:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Let 's get started. Producer / Consumer Test Started. CrunchifyBlockingProducer: Message - i' m msg 1 produced . CrunchifyBlockingProducer : Message - i 'm msg 2 produced. CrunchifyBlockingConsumer: Message - i' m msg 1 consumed . CrunchifyBlockingConsumer : Message - i 'm msg 2 consumed. CrunchifyBlockingProducer: Message - i' m msg 3 produced . CrunchifyBlockingConsumer : Message - i 'm msg 3 consumed. CrunchifyBlockingProducer: Message - i' m msg 4 produced . CrunchifyBlockingConsumer : Message - i 'm msg 4 consumed. CrunchifyBlockingProducer: Message - i' m msg 5 produced . CrunchifyBlockingProducer : Exit Message - All done from Producer side . Produced 50 CrunchifyMessages CrunchifyBlockingConsumer : Message - i ' m msg 5 consumed . CrunchifyBlockingConsumer : Message - All done from Producer side . Produced 50 CrunchifyMessages consumed . |
언제 java.util.concurrent.BlockingQueue를 사용해야 합니까?
- 어떤 종류의 들어오는 요청을 조절하려면 같은 것을 사용해야합니다
- 생산자는 무제한 대기열로 소비자보다 훨씬 앞서 나갈 수 있습니다. 소비자가 생산자를 따라잡지 않으면
OutOfMemoryError
가 발생할 수 있습니다. 이러한 상황에서는 잠재 생산자에게 대기열이 가득 찼다는 신호를 보내고 실패하면 빨리 포기하는 것이 좋습니다.- 즉, 생산자는 자연스럽게 제한됩니다.
- 블로킹 큐는 일반적으로 동시 응용 프로그램에서 사용됩니다.
- 정확하고 스레드로부터 안전한 구현을 제공합니다.
- 메모리 소비도 제한되어야 합니다.