2012-02-17 2 views
4

자바에서 ByteBuffer을 얻었습니다.이 바이트를 읽은 다음 조건부로 수정하려고합니다.Java에서 ByteBuffer의 일부를 원자 적으로 읽은 다음에 읽으십시오.

public void updateByte(int index) { 
    byte b = this.buffer.getByte(index); 

    if (b == someByteValue) { 
     this.buffer.setByte(index, someNewByte); 
    } 
} 

바이트를 읽고 수정하는 것이 어떻게 자동으로 이루어 지도록 할 수 있습니까?

여러 스레드가 동시에 다른 바이트의 버퍼를 쓸 수 있기 때문에 전체 ByteBuffer 또는 updateByte 메서드를 동기화하고 싶지 않습니다. 즉, updateByte을 여러 스레드에서 동시에 호출 할 수 있습니다. 오랫동안 index가 다른 경우).

사용중인 ByteBuffer가 바이트 []에 의해 뒷받침되지 않으므로 위의 예에서 bb.hasArray() == false입니다.

답변

3

짧은 대답을 비교하고 교환 할 (대부분의 JVM)에 안전하지 않은 사용할 수 있습니다 : 당신이 할 수없는, 의지하지 않고 JNI에.

길게 대답 : ByteBuffer API에는 원자 적 업데이트가 없습니다. 더욱이, ByteBuffer와 메모리의 상호 작용은 엄격하게 정의되지 않습니다. 그리고 Sun 구현에서 원시 메모리에 액세스하는 데 사용되는 방법으로는 캐시를 플러시하지 않으므로 멀티 코어 프로세서에서 오래된 결과가 표시 될 수 있습니다.

또한 Buffer (및 ByteBuffer와 같은 하위 클래스)은 스레드로부터 안전하지 않다고 명시 적으로 설명됩니다. 동일한 버퍼에 여러 스레드가 액세스하는 경우 (1) 절대 액세스에 대한 구현 동작을 사용하거나 (2) 상대 액세스를 위해 깨진 코드를 작성하는 경우입니다.

+0

FileChannel (스레드 세이프)에서 만든 MappedByteBuffer를 사용하게 될 것이므로 매핑 된 버퍼는 안전합니다. –

+1

@Dave - MappedByteBuffer는 파일을 생성하는 데 사용 된 FileChannel에 연결되어 있지 않습니다. 후자는 단순히 * mmap * 시스템 호출에 인수를 제공하는 데 사용됩니다. – kdgregory

+0

java.util.concurrent.lock.ReadWriteLock의 인스턴스를 만들고 사용할 수 있습니다. 특정 '원자 바이트'또는 '원자 바이트 영역'을 읽거나 쓰는 모든 코드가 먼저 해당 바이트/영역에 해당하는 잠금을 가져옵니다. :) –

3

Java에서 원자 적으로 바이트에 액세스 할 수 있다고 생각하지 않습니다. 가장 좋은 방법은 int 값을 수정하는 것입니다. 이렇게하면 단일 바이트 수정을 시뮬레이션 할 수 있습니다.

당신은 배열() (힙의 ByteBuffer) 또는 주소() (직접의 ByteBuffer)

5

ByteBuffer의 일부에 대해 명시적인 잠금 개체 집합을 제공하는 방법 (일부는 매우 작을 수 있습니다 (예 : 한 단어 또는 상당히 큰, 예 : 4 쿼터 버퍼)?

스레드가 바이트를 확인하고 수정하려면 먼저 해당 부분에 대한 잠금을 획득하고 작업을 수행 한 다음 잠금을 해제해야합니다.

이렇게하면 전역 동기화가 필요없이 여러 스레드가 데이터의 다른 부분에 액세스 할 수 있습니다.

1

개인적으로 데이터를 쓰고 뮤텍스를 릴리스 할 때까지 오프셋을 알아낼 때까지 개인적으로 뮤텍스를 잠급니다. 이렇게하면 잠시 동안 잠글 수 있습니다.

0

ByteBuffer를 잠글 수 있어야합니다. 메소드 :

  • 잠금 객체 목록을 생성하고 바이트 버퍼 읽기 당 하나의 영역 만 잠글 수 있습니다. DNA와 마찬가지로 제안은 가장 빠른 솔루션이어야합니다.
  • 또는 심지어 memory mapping to solve this을 사용하고 FileChannel.lock을 사용하여 바이트 버퍼의 영역을 잠글 수는 있지만 더 낮은 수준으로 설정할 수도 있습니다. 편집 : 외부 프로그램의 액세스 만 보호합니다. IMO
  • 또는 더 작지만 동기화 된 ByteBuffers + 교환 정보를 사용할 수 있습니다.

    대답은해야한다 "그것은이 list에서 동시 DirectByteBuffer에 대한

1

긴 긴 스레드 (필자는 mmap에 아이디어를 얻었다 곳이다) 서로 변경 사항을 즉시 볼 수 스레드 interesting to note입니다 예".

또 다른 큰 예는 NIO.2입니다. 쓰기/읽기 작업이 바이트 버퍼를 제출하면 CompletionHandler가 호출 될 때 정상입니다.

NIO.2의 경우 DirectByteBuffer 만 적용됩니다. DirectByteBuffer에 "Cloned"한 Non-Direct-ByteBuffer의 경우, 실제의 저레벨 조작의 파라미터는 아니다.

0

코드의 중요한 부분을 잠금 제어에 두는 것이 깨끗한 솔루션이어야한다고 생각합니다. 그러나 유스 케이스가 쓰기에 비해 읽기 수가 많으면 동기화를 직접 사용하지 마십시오. 솔루션의 일부로 ReentrantReadWriteLock을 사용하는 것이 좋습니다. ByteBuffer를 수정하는 함수에서 writeLock(). lock()과 코드를 가져옵니다. 그리고 읽기는 readLock(). lock()을 사용합니다. 언급 된 링크에서 읽기 - 쓰기 잠금에 대해 더 많이 읽을 수 있습니다. 기본적으로 동시 읽기는 허용되지만 동시 쓰기는 허용되지 않고 쓰기가 진행되는 동안 읽기 스레드 대기

관련 문제