< 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,11 +22,12 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
 
 package java.io;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+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,19 +67,25 @@
      * 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
+     * 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
-        AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
-        AtomicReferenceFieldUpdater.newUpdater
-        (BufferedInputStream.class,  byte[].class, "buf");
+    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,13 +217,13 @@
      * 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)
+        if (markpos < 0) {
             pos = 0;            /* no mark: throw away the buffer */
-        else if (pos >= buffer.length)  /* no room left in 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,20 +237,22 @@
                         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)) {
+                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,11 +483,11 @@
      * @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)) {
+            if (UNSAFE.compareAndSwapObject(this, BUF_OFFSET, buffer, null)) {
                 InputStream input = in;
                 in = null;
                 if (input != null)
                     input.close();
                 return;
< prev index next >