java 1.5부터는 Concurrent 패키지가 도입되었습니다. 안 쓸 이유가 없을 겁니다. 왜냐하면, wait와 notify를 이용해서 관리하는 게 쉽지 않기 때문입니다. 제가 생활 코딩에 올린 일련의 글들을 보면 알 수 있습니다.

 

 


 이번 시간에는 그 중 첫번째인 ArrayBlockingQueue를 알아보겠습니다. 이것은 BlockingQueue를 implements한 클래스입니다. Blocking이라고 하면 블록을 하는 것을 의미합니다. 큐이긴 큐인데, 넣는 연산도, 빼는 연산도 조건에 맞지 않으면 맞을 때 까지 대기할 수 있게끔 한 클래스입니다. 그런데, 이것을 구현한 구현체가 Array 어쩌고입니다. 보통 배열은 크기가 정해졌을 때 많이 써 먹으니, 버퍼의 크기가 정해진 생산자 소비자 문제에서 쓰면 좋겠네요.

 

 그런데, 이 문제는 제가 옛날에 썼던 에도 있었습니다. 그런데 왜 굳이 소개를 할까요? 글에 소개했던 방법에 비해 매우 간단하기 때문입니다.

 

 

 Main 클래스는 거의 동일합니다. 1000개의 테스트 케이스를 가지고, Consumer와 Producer가 제대로 동작하는지를 확인합니다.

 

 

 그리고 Producer입니다. 그냥 저는 put 메서드만 호출하였습니다.

 

 

 put 메서드는, 특별한 원소를 queue 안에다가 넣습니다. 그런데, space가 꽉 차면 넣지 못할 겁니다. 그러면 어떻게 할까요? 넣을 수 있을 때 까지 기다립니다. block 함수라는 이야기입니다. 

 

 

 그리고, 소비자 클래스에서는, take 메서드만 호출하였습니다.

 

 

 이것 역시, 제거할 element가 없으면 생길 때 까지 대기합니다. blocking 함수라는 의미입니다. 즉, take와 put은 서로 상성이 맞는 쌍이라는 이야기입니다. 하나는 원소가 없으면, 추가될 때 까지 기다리고, 다른 하나는 꽉 차면 뭔가가 제거될 때 까지 기다리는 식입니다.

 

 

 프로그램을 실행해 보면, 매우 잘 됨을 알 수 있습니다. 단지, 우리는 소비자와 생산자 클래스에서 각각 take와 put만 호출했을 뿐입니다. 분명 이 글에서 notify랑 wait를 호출하는 것에 비하면 매우 간단하다는 것을 알 수 있습니다. 사실 이게 제일 중요한 부분이기도 합니다.

 


 그런데, 원소를 추가하는 다른 메서드들도 있다는 것을 알 수 있습니다. 이 중에, non block 쌍인 offer, poll 메서드가 있습니다.

 

 먼저, offer는 원소를 추가하는데, 추가 가능한 상태가 아니면 false를 리턴합니다. 그러면, 해당 원소가 추가될 때 까지 계속 돌리려면 어떻게 하면 될까요? while loop를 잘 이용하시면 됩니다.

 

 

 이런 식으로 쓰면 됩니다. carrot을 추가하지 못해서 false가 떨어지면 while loop를 돌리면 됩니다. 그렇지 않으면 추가된 것이니 루프를 빠져 나오게끔 하시면 됩니다.

 

 

 poll은 큐에서 원소 하나를 빼는데, 없으면 null을 즉시 리턴합니다.

 

 

 마찬가지로, 꺼내올 때에는 bq.poll() 값이 null값이면 계속 loop를 돌리게끔 하면 되겠네요.

 

 

 실행 결과는 위와 같습니다. 당연하게도 x초 대기해 보고 null값이나 false를 리턴하는 방법도 있을 겁니다.

 

 

 얼마 동안 기다릴 것인지를 넣어주면, 해당 시간동안 먼저 기다립니다. 예를 들어, unit에 TimeUnit.SECONDS를, timeout에 2를 넣으면, 2초동안 기다립니다. 그 동안에 넣는 것을 성공하면 true를, 아니면 false를 리턴합니다.

 

 

 poll에다가, timeout과 unit을 추가하면 어떻게 될까요? 설명을 잘 보면 위에서 언급한 offer와 크게 다르지 않다는 것을 알 수 있습니다. 예를 들어 unit에 TimeUnit.SECONDS를 넣고, timeout에 2를 넣으면, 2초까지 기다려 봅니다. 그 전에 제거가 되면 제거된 원소를, 아니면 null을 리턴합니다.

 


 

 큐의 맨 앞에 있는 원소를 가져오기만 하고 제거를 하지 않아야 하는 경우가 있는데요. 이 경우에는 peek 메서드를 쓰시면 됩니다. fair에 대한 것은 다음에 이어서 해 보도록 하겠습니다.