< 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 >