2012-06-22 3 views
9

Quali opzioni devo rendere sicuro un thread ByteBuffer? È noto che non è thread-safe poiché mette in sicurezza posizione, limite e alcuni metodi (/ all?) Dipendono da questo stato interno.Opzioni per rendere sicuro il thread di ByteBuffer di Java

Per i miei scopi sarà sufficiente se più thread di lettura sono sicuri, ma per altri futuri visitatori mi piacerebbe sapere quali tecniche/trucchi/trappole devo sapere per renderlo completamente sicuro.

Quello che ho in mente:

  • Sincronizzazione o utilizzando serrature ReadWrite per tutti i metodi. Probabilmente l'approccio più lento (?)
  • Sottoclasse ByteBuffer ed evitare lo stato persistente legato al thread come posizione ecc. E generare eccezioni di conseguenza per tutti i metodi che devono utilizzare lo stato interno. Questo sarebbe il digiuno. Ma ci sono trappole? (eccetto che dovrò leggere la memoria mappata direttamente nella memoria dell'heap ...)

Quali altri trucchi posso usare? Come potrei ad esempio implementare un "clone bytes on read" con DirectBuffer - è possibile a tutti? Probabilmente affettare l'intero ByteBuffer (ByteBuffer.slice) in una soluzione?

Aggiornamento: cosa si intende in questo question con "duplicato (mentre sincronizzato) per ottenere una nuova istanza indicando gli stessi byte mappati"

+1

Preferisco utilizzare un modello di attore in cui qualsiasi ByteBuffer viene aggiornato da un solo thread (o è di sola lettura). Il motivo per cui lo faccio è che ho riscontrato che il sovraccarico della sincronizzazione supera di solito i vantaggi di avere più thread. –

+0

grazie, peter! stai usando questo attraverso una fetta? o come accedi agli stessi dati? – Karussell

+0

Non uso una slice, invece utilizzo un wrapper che nasconde tutto (anche il fatto che sto usando ByteBuffers e potrei voler passare a Unsafe che è leggermente più veloce) Il vantaggio di usare un wrapper è che puoi nascondere tutto i dettagli e accedi al tuo "array" in modo naturale chiamando metodi. Ciò è particolarmente utile in quanto ho array con miliardi di elementi che non rientrano in un singolo ByteBuffer. –

risposta

11

A Buffer classe potrebbe essere thread-safe ... nel senso che le singole operazioni erano correttamente sincronizzate, eccetera. Tuttavia, l'API non è progettata pensando a più thread, quindi questa è probabilmente una perdita di tempo.

Il problema di base è che le singole operazioni su un buffer sono troppo sottili per essere l'unità di sincronizzazione. Un'applicazione non può sincronizzare in modo significativo a livello di operazioni get e put, o flip, posizione e così via. In generale, un'applicazione deve eseguire le sequenze di queste operazioni atomicamente per sincronizzarsi in modo efficace.

Il secondo problema è che se si esegue la sincronizzazione a un livello fine, è probabile che si aggiungano spese generali significative alle chiamate al metodo. Dal momento che l'utilizzo delle API del buffer deve eseguire l'I/O in modo efficiente, ciò vanifica lo scopo.


Se necessario sincronizzare l'accesso thread a un buffer condiviso, è meglio usare sincronizzazione esterna; per esempio. qualcosa di simile:

synchronized (someLock) { 
     buffer.getByte(); 
     buffer.getLong(); 
     ... 
    } 

condizione tutte le discussioni che utilizzano un dato buffer di sincronizzare correttamente (ad esempio utilizzando lo stesso oggetto serratura), non importa che il buffer non è thread-safe. La sicurezza del filo viene gestita esternamente all'oggetto buffer e in modo più granuloso.


Come commenti sottolineano, si potrebbe anche usare ByteBuffer.slice() o buffer.asReadOnlyBuffer() per darvi un altro buffer con quello esistente come supporto. Tuttavia, i javadoc non garantiscono la sicurezza del thread in entrambi i casi.In effetti, la javadocs per Buffer fare questa dichiarazione coperta:

buffer non sono sicuri per l'uso da parte di più thread simultanei. Se un buffer deve essere utilizzato da più di un thread, l'accesso al buffer deve essere controllato mediante la sincronizzazione appropriata.

+0

vuoi commentare il caso buffer di sola lettura? – Karussell

+0

Non penso che il caso di sola lettura semplifica le cose , a meno che non si sia pronti a trattare il buffer come un semplice array ... recuperare e utilizzare l'array di supporto direttamente tramite 'array()'. Anche in questo caso è necessario sincronizzarsi per garantire che l'accesso alla memoria sia costante. –

+1

come potrebbe essere incoerente quando non esiste nessuna scrittura, anche l'array di supporto non è sempre esistente – Karussell