lock immutable concurrent java immutability nio

java - immutable - ¿Cómo evitar hacer copias defensivas de ByteBuffer?



java lock (4)

Tengo una clase que toma un ByteBuffer como un argumento de constructor. ¿Hay alguna manera de evitar hacer copias defensivas para garantizar que el búfer no se modifique más allá de ese punto?

ByteBuffer.isReadOnly () no garantiza que el propietario original no modifique el búfer. Para empeorar las cosas, no parece haber una forma de subclasificar ByteBuffer. ¿Algunas ideas?


Esto es lo mejor que podría hacer por ahora:

/** * Helper functions for java.nio.Buffer. * <p/> * @author Gili Tzabari */ public final class Buffers { /** * Returns a ByteBuffer that is identical but distinct from the original buffer. * <p/> * @param original the buffer to copy * @return an independent copy of original * @throws NullPointerException if original is null */ public static ByteBuffer clone(ByteBuffer original) { Preconditions.checkNotNull(original, "original may not be null"); ByteBuffer result = ByteBuffer.allocate(original.capacity()); ByteBuffer source = original.duplicate(); source.rewind(); result.put(source); try { source.reset(); result.position(source.position()); result.mark(); } catch (InvalidMarkException unused) { // Mark is unset, ignore. } result.position(original.position()); result.limit(original.limit()); return result; } /** * Returns an array representation of a buffer. The returned buffer may, or may not, be tied to * the underlying buffer''s contents (so it should not be modified). * <p/> * @param buffer the buffer * @return the remaining bytes */ public static byte[] toArray(ByteBuffer buffer) { if (buffer.hasArray() && !buffer.isReadOnly() && buffer.position() == 0 && buffer.remaining() == buffer.limit()) { return buffer.array(); } ByteBuffer copy = buffer.duplicate(); byte[] result = new byte[copy.remaining()]; copy.get(result); return result; } /** * Prevent construction. */ private Buffers() { } }

También he presentado una solicitud de función con Oracle: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7130631


Esto no responde a la pregunta, pero, para algunos usos (por ejemplo, si está tratando de hacer cumplir el "diseño por contrato") puede ser lo suficientemente bueno y más eficiente. Para otros usos, no funcionará y puede ser mucho menos eficiente.

Durante su constructor, guarde el código hash del ByteBuffer

final int originalBBHashCode = byteBuffer.hashCode ();

Luego, en los pocos lugares críticos de su código donde desea verificar que ByteBuffer no ha cambiado, verifique que byteBuffer.hashCode () == originalBBHashCode. Si no, lanza una excepción. Francamente, me siento tentado a lanzar una excepción de modificación de modalidad concurrente, ya que ese es el comportamiento que estás imitando, pero YMMV.


No evita una copia, pero quizás:

  1. Utilice un conjunto precargado de ByteBuffers preasignados
  2. Permita que el constructor de la clase del Autor permita una ''copia'' del ByteBuffer entrante, pero haga que la clase use un ByteBuffer del grupo para mover los costos de asignación / desconexión al inicio / cierre de la aplicación. Solo paga un coste de copia de esta manera.

La única forma real es, como usted dice, buf.asReadOnlyBuffer() , luego pase esto al constructor. No hay otra opción aparte de esto, aunque podría hacer una copia del contenido en un nuevo ByteBuffer , luego pasarlo.