< prev index next >
src/java.base/share/classes/java/io/BufferedInputStream.java
Print this page
rev 13994 : 8153334: Replace BufferedInputStreams use of AtomicReferenceFieldUpdater with Unsafe
Reviewed-by: alanb, forax
*** 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
*** 66,84 ****
* 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
--- 67,91 ----
* a different size.
*/
protected volatile byte buf[];
/**
! * Get Unsafe and offset of buf to provide compareAndSet functionality.
! * 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 Unsafe UNSAFE = Unsafe.getUnsafe();
! private static final long BUF_OFFSET;
! static {
! try {
! BUF_OFFSET = UNSAFE.objectFieldOffset(
! BufferedInputStream.class.getDeclaredField("buf"));
! } catch (ReflectiveOperationException e) {
! throw new Error(e);
! }
! }
/**
* The index one greater than the index of the last valid byte in
* the buffer.
* This value is always
*** 210,222 ****
* This method also assumes that all data has already been read in,
* hence pos > count.
*/
private void fill() throws IOException {
byte[] buffer = getBufIfOpen();
! if (markpos < 0)
pos = 0; /* no mark: throw away the buffer */
! else if (pos >= buffer.length) /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
--- 217,229 ----
* This method also assumes that all data has already been read in,
* hence pos > count.
*/
private void fill() throws IOException {
byte[] buffer = getBufIfOpen();
! if (markpos < 0) {
pos = 0; /* no mark: throw away the buffer */
! } else if (pos >= buffer.length) { /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
*** 230,249 ****
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;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
}
--- 237,258 ----
pos * 2 : MAX_BUFFER_SIZE;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
! if (!UNSAFE.compareAndSwapObject(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;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
+ }
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
}
*** 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;
--- 483,493 ----
* @exception IOException if an I/O error occurs.
*/
public void close() throws IOException {
byte[] buffer;
while ( (buffer = buf) != null) {
! if (UNSAFE.compareAndSwapObject(this, BUF_OFFSET, buffer, null)) {
InputStream input = in;
in = null;
if (input != null)
input.close();
return;
< prev index next >