>

요청-응답 프로토콜을 고려하십시오.

우리는 select() 를 수행하는 스레드를 생성  허용 된 비 차단 SocketChannel 에서 읽고 쓰는 루프 . 다음과 같이 보일 수 있습니다

while (!isStopped()) {
    selector.select();
    Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
    while (selectedKeys.hasNext()) {
        SelectionKey selectedKey = selectedKeys.next();
        selectedKeys.remove();
        Context context = (Context) selectedKey.attachment();
        if (selectedKey.isReadable()) {
            context.readRequest();
        } else /* if (selectedKey.isWritable()) */ {
            context.writeResponse();
        }
    }
}

여기서 Context  해당 SocketChannel 의 컨테이너 일뿐입니다. 버퍼와 로직을 읽고 쓸 수 있습니다. readRequest  다음과 같이 보일 수 있습니다

public void readRequest() {
    // read all content
    socketChannel.read(requestBuffer);
    // not interested anymore
    selectionKey.interestOps(0);
    executorService.submit(() -> {
        // handle request with request buffer and prepare response
        responseBuffer.put(/* some response content */); // or set fields of some bean that will be serialized
        // notify selector, ready to write
        selectionKey.interestOps(SelectionKey.OP_WRITE);
        selectionKey.selector().wakeup(); // worried about this
    });
}

다시 말해, 우리는 소켓 채널에서 읽고 버퍼를 채우고 다른 스레드로 핸들링을 전달합니다. 이 스레드는 처리를 수행하고 응답 버퍼에 저장하는 응답을 준비합니다. 그런 다음 셀렉터에게 쓰고 싶다는 알림을 표시하고 활성화합니다.

Selector#wakeup() 는 이전에 발생한 관계를 언급하지 않으므로 선택기 스레드가 응답 버퍼 (또는 일부 중간 객체)가 일치하지 않는 상태로 보일 수 있습니다.

가능한 시나리오입니까? 그렇다면 SocketChannel 에 기록 할 응답을 전달하는 올바른 방법은 무엇입니까   Selector 에 의해  루프 스레드? (일부 volatile 를 통해 응답 게시  들? SelectionKey 사용  부착? 다른 형태의 동기화?)

  • 답변 # 1

    Selector 에 관한 문서  다음과 같이 말합니다 :

    와이즈 비즈

    happens-before관계는synchronizes-with관계를 포함하는 것으로 Java 언어 사양의 17 장에 정의되어 있습니다.

    그래도 첨부 된 객체에서 올바르게 동기화해야합니다. 그것이 당신의 목표이고, 당신의 의무입니다. 코드 만

    The selection operations synchronize on the selector itself, on the key set, and on the selected-key set, in that order.

    에 기록한다고 가정  실행기 스레드에서, 선택기 스레드 만이후읽은 후 쓰기 가용성에 관심이 있다고 말하면 동기화가 충분합니다.

    놀라운 점은 responseBuffer 에서 동기화를 받고 있다는 것입니다. interestOps(...) 이전에도 .

    <시간>

    내 경험에 따르면 라이브러리 유틸리티 (이 경우 선택기)를 통해 적절한 동기화를 얻는 데 어려움을 겪고 있다면 객체를 직접 동기화하는 것이 좋습니다. wakeup() 와 함께  객체 자체에 대한 진술, synchronize , 개체의 작업 등에 사용하는 다른 일반적인 동기화 개체 등. 침착하게 유지하기 위해 성능이 약간 저하됩니다 (실제로 보호 섹션 내에서 차단하지 않는다고 가정 할 경우 거의 중요하지 않음).

  • 답변 # 2

    먼저, 선택자에게 쓰기를 원한다고 알리지 않아도됩니다. 당신은 단지 작성합니다. 쓰기가 0을 반환 한 경우에만 선택기 또는 해당 스레드를 포함해야합니다.

    두 번째로, 다음과 같이 동기화를 수행하는 경우 선택기의 세 가지 수준의 동기화의 결과로 발생 전 관계가 발생합니다.

    귀하의 코드는 ReentrantLock 에서차단할 수 있습니다  선택기가 현재 선택중인 경우 호출합니다. Javadoc에서는 가능성을 배제하지 않습니다. 올바른 순서로 작업을 수행해야합니다.

    <올>

    웨이크 업.

    선택기에서 동기화하십시오.

    와이즈 비즈에게 전화 .

    (2)와 선택기 자체의 내부 동기화의 조합은 필요한 이전에 관계를 설정합니다.

    interestOps()

관련 자료

  • 이전 php - Ubuntu에서 조수와 함께 작동하도록 YaxGUI를 설치하는 방법은 무엇입니까?
  • 다음 python 2.7 - simpy - 여러 (비특이적) 리소스 요청 및 요청 순서