< prev index next >

src/java.base/share/classes/java/io/BufferedInputStream.java

Print this page
rev 17627 : 8185362: Replace use of AtomicReferenceFieldUpdater from BufferedInputStream with Unsafe
Reviewed-by: shade, martin

*** 22,32 **** * or visit www.oracle.com if you need additional information or have any * questions. */ package java.io; ! import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to --- 22,33 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ package java.io; ! ! import jdk.internal.misc.Unsafe; /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to
*** 58,84 **** * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; /** * The internal buffer array where the data is stored. When necessary, * it may be replaced by another array of * a different size. */ ! protected volatile byte buf[]; ! ! /** ! * Atomic updater to provide compareAndSet for buf. This is ! * necessary because closes can be asynchronous. We use nullness ! * of buf[] as primary indicator that this stream is closed. (The ! * "in" field is also nulled out on close.) ! */ ! private static final ! AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = ! AtomicReferenceFieldUpdater.newUpdater ! (BufferedInputStream.class, byte[].class, "buf"); /** * The index one greater than the index of the last valid byte in * the buffer. * This value is always --- 59,85 ---- * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; + private static final Unsafe U = Unsafe.getUnsafe(); + + private static final long BUF_OFFSET + = U.objectFieldOffset(BufferedInputStream.class, "buf"); + /** * The internal buffer array where the data is stored. When necessary, * it may be replaced by another array of * a different size. */ ! /* ! * We null this out with a CAS on close(), which is necessary since ! * closes can be asynchronous. We use nullness of buf[] as primary ! * indicator that this stream is closed. (The "in" field is also ! * nulled out on close.) ! */ ! protected volatile byte[] buf; /** * The index one greater than the index of the last valid byte in * the buffer. * This value is always
*** 228,240 **** } else { /* grow buffer */ int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? pos * 2 : MAX_BUFFER_SIZE; if (nsz > marklimit) nsz = marklimit; ! byte nbuf[] = new byte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); ! if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. // But for now, the only way CAS can fail is via close. // assert buf == null; --- 229,241 ---- } else { /* grow buffer */ int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? pos * 2 : MAX_BUFFER_SIZE; if (nsz > marklimit) nsz = marklimit; ! byte[] nbuf = new byte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); ! if (!U.compareAndSetObject(this, BUF_OFFSET, buffer, nbuf)) { // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. // But for now, the only way CAS can fail is via close. // assert buf == null;
*** 474,484 **** * @exception IOException if an I/O error occurs. */ public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { ! if (bufUpdater.compareAndSet(this, buffer, null)) { InputStream input = in; in = null; if (input != null) input.close(); return; --- 475,485 ---- * @exception IOException if an I/O error occurs. */ public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { ! if (U.compareAndSetObject(this, BUF_OFFSET, buffer, null)) { InputStream input = in; in = null; if (input != null) input.close(); return;
< prev index next >