문제

개체의 차단 대기열이 있습니다.

대기열에 개체가 있을 때까지 차단되는 스레드를 작성하고 싶습니다.BlockingQueue.take()에서 제공하는 기능과 유사합니다.

하지만 객체를 성공적으로 처리할 수 있을지 모르기 때문에 객체를 제거하지 않고 그냥 peek()만 하고 싶습니다.성공적으로 처리할 수 있는 경우에만 개체를 ​​제거하고 싶습니다.

그래서 차단 peek() 기능을 원합니다.현재 peek()는 javadocs에 따라 대기열이 비어 있으면 반환합니다.

뭔가 빠졌나요?이 기능을 달성하는 다른 방법이 있습니까?

편집하다:

방금 스레드 안전 큐를 사용하고 대신 엿보고 잠을 잤는지에 대해 어떻게 생각하시나요?

public void run() {
    while (!exit) {
        while (queue.size() != 0) {
            Object o =  queue.peek();
            if (o != null) {
                if (consume(o) == true) {
                    queue.remove();
                } else {
                    Thread.sleep(10000); //need to backoff (60s) and try again
                }
            }
        }
        Thread.sleep(1000); //wait 1s for object on queue
    }
}

소비자 스레드 하나와 (별도의) 생산자 스레드 하나만 있습니다.BlockingQueue를 사용하는 것만큼 효율적이지는 않은 것 같습니다.어떤 의견이라도 감사드립니다.

도움이 되었습니까?

해결책

당신은 LinkedBlockingDeque 그리고 대기열에서 항목을 물리적으로 제거합니다(다음을 사용). takeLast()) 하지만 에서 다시 교체하세요. 대기열의 끝 다음을 사용하여 처리가 실패하는 경우 putLast(E e).그 사이에 "생산자"는 앞쪽 다음을 사용하여 대기열의 putFirst(E e).

항상 이 동작을 자신의 내부에 캡슐화할 수 있습니다. Queue 구현 및 제공 blockingPeek() 수행하는 방법 takeLast() 이어서 putLast() 기본에 대한 비하인드 스토리 LinkedBlockingDeque.따라서 호출 클라이언트의 관점에서 볼 때 해당 요소는 대기열에서 제거되지 않습니다.

다른 팁

하지만 객체를 성공적으로 처리할 수 있을지 모르기 때문에 객체를 제거하지 않고 그냥 peek()만 하고 싶습니다.성공적으로 처리할 수 있는 경우에만 개체를 ​​제거하고 싶습니다.

일반적으로 스레드로부터 안전하지 않습니다.만약에, 너 다음에는? peek() 개체가 성공적으로 처리될 수 있는지 확인합니다. 하지만 그 전에 take() 제거하고 처리하려면 다른 스레드가 해당 개체를 가져가나요?

내가 아는 유일한 것은 이 일을 한다는 것이다. 블로킹버퍼 ~에 Apache 공용 컬렉션:

빈 버퍼에서 get 또는 remod가 호출되면 호출 스레드는 ADD 또는 ADDALL 작업이 완료되었다는 알림을 기다립니다.

get() 는 다음과 같습니다 peek(), 그리고 Buffer 다음과 같이 행동하도록 만들 수 있습니다. BlockingQueue 장식함으로써 무제한Fifo버퍼BlockingBuffer

차단 대기열에 이벤트 리스너 대기열을 추가한 다음 (차단) 대기열에 무언가가 추가되면 리스너에게 이벤트를 보낼 수도 있습니까?actionPerformed 메소드가 호출될 때까지 스레드 블록을 가질 수 있습니다.

빠른 대답은 실제로 차단 peek()를 사용하여 차단 큐를 구현하는 바를 차단하는 방법이 없다는 것입니다.

뭔가 빠졌나요?

peek()는 동시성에 문제가 있을 수 있습니다.

  • peek()된 메시지를 처리할 수 없는 경우 소비자가 여러 명인 경우를 제외하고 해당 메시지는 대기열에 남게 됩니다.
  • 당신이 처리할 수 없다면 누가 그 객체를 대기열에서 꺼내겠습니까?
  • 소비자가 여러 명인 경우 peek()'ing과 항목을 처리하는 다른 스레드 사이에 경쟁 조건이 발생하여 중복 처리가 발생하거나 더 악화됩니다.

실제로 항목을 제거하고 다음을 사용하여 처리하는 것이 더 나을 것 같습니다.책임 사슬 패턴

편집하다:답장:마지막 예:소비자가 1명뿐이라면 중간에 업데이트되지 않는 한 대기열에 있는 객체를 절대 제거하지 못할 것입니다. 이 경우 스레드 안전에 매우 주의하는 것이 좋으며 아마도 항목을 넣지 말았어야 했습니다. 어쨌든 대기열에 있습니다.

BlockingQueue 자체에는 귀하가 지정하는 기능이 없는 것 같습니다.

그래도 문제를 조금 재구성하려고 할 수 있습니다."올바르게 처리"할 수 없는 개체를 어떻게 하시겠습니까?그냥 대기열에 남겨두는 경우에는 어느 시점에서 꺼내서 처리해야 합니다.처리 방법을 알아내거나(일반적으로 queue.get()이 유효하지 않거나 잘못된 값을 제공하는 경우 바닥에 놓아도 괜찮을 것입니다) 다른 데이터 구조를 선택하는 것이 좋습니다. FIFO.

답변 자체는 아니지만 다음과 같습니다. JDK-6653412 이는 유효한 사용 사례가 아니라고 주장합니다.

'가장 간단한' 솔루션

처리하지 마십시오. 다음 요소까지 이전의 요소가 성공적으로 처리되었습니다.

public void run() {

Object lastSuccessfullyProcessedElement = null;

    while (!exit) {
        Object obj =  lastSuccessfullyProcessedElement == null ? queue.take() : lastSuccessfullyProcessedElement; // blocking

        boolean successful = process(obj);

        if(!successful) {
            lastSuccessfullyProcessedElement = obj;
        } else {
            lastSuccessfullyProcessedElement = null;
        }
    }
}
  1. 부름 peek() 값이 null인지 확인하는 것은 CPU 효율적이지 않습니다.

다음 프로그램에 대한 대기열이 비어 있을 때 내 시스템에서 CPU 사용량이 10%로 증가하는 것을 보았습니다.

while (true) {
   Object o = queue.peek();
   if(o == null) continue;
   // omitted for the sake of brevity
}
  1. 첨가 sleep() 느림을 더해줍니다.

  2. 다음을 사용하여 대기열에 다시 추가 putLast 질서를 어지럽힐 것이다.또한 잠금이 필요한 차단 작업입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top