크기를 확인하고 작업을 수행 - 그것은 ConcurrentLinkedDeque에 대한 안전합니까?

Izbassar Tolegen :

나는의 첫 번째 값을 교체해야 Deque크기가 제한을 초과하는 경우에만, 새 값으로. 나는 그것을 해결하기 위해이 코드를 썼다 :

final class Some {
    final int buffer;
    final Deque<Operation> operations = new ConcurrentLinkedDeque<>();
    // constructors ommited;

    @Override
    public void register(final Operation operation) {
        if (this.operations.size() == this.buffer) {
            // remove the oldest operation
            this.operations.removeFirst();
        }
        // add new operation to the tail
        this.operations.addLast(operation);
    }

    @Override
    public void apply() {
        // take the fresh operation from tail and perform it
        this.operations.removeLast().perform();
    }
}

보시다시피, 나는 두 가지 방법, 즉 수정합니다 있습니다 Deque. 이 코드는 멀티 스레드 환경에서 제대로 작동하는지, 의문을 가지고있다. 질문 : 그것은을 확인하는 것이 안전합니다 size(), 수정 그 다음 작업을 수행 ConcurrentLinkedDeque이후에? 나는 가능한 한 최소한 잠금을 갖고 싶어. 이 코드는 작동하지 않습니다 그렇다면, 나는 잠금 소개했다 다음의 사용에 아무 문제가 없다 ConcurrentLinkedDeque().

final class Some {
    final int buffer;
    final Deque<Operation> operations = new LinkedList<>();
    final Lock lock = new ReentrantLock();
    // constructors ommited;

    @Override
    public void register(final Operation operation) {
        this.lock.lock();
        try {
            if (this.operations.size() == this.buffer) {
                // remove the oldest operation
                this.operations.removeFirst();
            }
            // add new operation to the tail
            this.operations.addLast(operation);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void apply() {
        this.lock.lock();
        try {
            // take the fresh operation from tail and perform it
            this.operations.removeLast().perform();
        } finally {
            this.lock.unlock();
        }
    }
}

이것은 함께 대안입니다 Lock. 유일한 방법은 내가 원하는 것을 달성하기 위해인가요? 나는 특히 동시 모음을 사용하려고 시도에 관심이 있어요.

양배추 :

그것이 올 때 동시 컬렉션은 스레드 안전 내부 상태. 즉, 그들은

  • 내부 상태가 손상 될 것이라는 점을 여러 스레드가 읽기 / 쓰기를 동시에 걱정없이 허용
  • 다른 스레드가 컬렉션을 수정하는 동안 반복 및 제거 허용
    • 모든 그러나. 나는 생각 CopyOnWriteArrayList들 ' Iterator지원하지 않는 remove()작업을
  • 보증 것들과 같은 일이-전에
    • 하나 개의 스레드에 의해 쓰기를 의미하는 것입니다 전에 발생 읽기 후속 스레드

그러나, 그들은은 하지 스레드 안전 에 걸쳐 외부 메소드 호출. 하나 메서드를 호출 할 때이 필요하지만, 그 잠금 시간 메서드가 반환을 출시 할 어떤 잠금 획득합니다. 당신이 조심하지 않으면 이것은으로 이어질 수 체크인 당시 행위의 경쟁 조건. 코드를 보면

if (this.operations.size() == this.buffer) {
    this.operations.removeFirst();
}
this.operations.addLast(operation);

다음과 같은 상황이 발생할 수 있습니다 :

  1. Thread-A 수표 크기 조건이 결과는 false
  2. Thread-A 새로운 추가로 이동 Operation
  3. 전에 Thread-A추가 할 수 있습니다 Operation, Thread-B에서 어떤 결과를 확인 크기 조건 false뿐만 아니라를
  4. Thread-B 새로운 추가 간다 Operation
  5. Thread-A 않는 새로운 추가Operation
    • 아니, 오! Operation추가 Thread-A일으키는 크기 임계 값에 도달 할
  6. Thread-B이미 과거 if문, 그것의 추가 Operation양단 큐가 너무 많은이 만드는 Operation

이유는 체크인 당시 행동은 당신이를 사용하여 두 번째 예에서와 외부 동기화가 필요합니다 Lock. 당신은 또한 사용할 수 있습니다 synchronized온 블록을 Deque.

귀하의 질문에 관련없는 : 당신은 전화를 Operation.perform()계속 유지하면서 두 번째 예에 Lock. 이것은 다른 스레드가 서로를 추가하려고 할 수 있습니다 의미 Operation받는 Deque동안 perform()실행합니다. 이것은 당신과 같이 코드를 변경할 수 있습니다 바람직하지 않은 경우 :

Operation op;

lock.lock();
try {
    op = deque.pollLast(); // poll won't throw exception if there is no element
} finally {
    lock.unlock();
}

if (op != null) {
    op.perform();
}

추천

출처http://43.154.161.224:23101/article/api/json?id=201554&siteId=1