階段性閱讀源代碼

來源:https://www.cnblogs.com/Mairr/p/7770662.html
1.簡介

  針對這一個版塊,主要做一個java8的源碼閱讀筆記。會對一些在javaWeb中應用比較廣泛的java包進行精讀,附上註釋。對於容易混淆的知識點給出相應的對比分析。
  精讀的源碼順序主要如下:

(1)第一部分:這部分是java開發的最常見包和類,要求精讀:

java.io
java.lang
java.util

 (2)第二部分:這一部分是java web開發的核心內容之一,要求要有深刻的理解。(包括了java的反射、網絡io、非阻塞、併發編程)————某些大牛說,這一部分運用的好壞,掌握的水平高低,會決定一個java開發程員的檔次:

java.lang.reflect
java.net
javax.net.*
java.nio
java.util.concurrent.*

(3)第三部分:這一部分要求不高,進行簡單泛讀,能看懂、會用即可:

java,lang.annotation
javax.annotation
java.lang.ref
java.math
java.rmi.*
javax.rmi.*
java.security.*
javax.security.*
java.sql
javax.sql.*
javax.transaction.*
java.test
java.xml.*
org.w3c.dom.*
org.xml.sax.*
javax.crypto.*
javax.imageio.*
javax.jws.*
java.util.jar
java.util.logging
java.util.prefs
java.util.regex
java.util.zip

2.源碼閱讀:—— day1:(java.io_BufferedInputStream類)

(1)java.io——BufferedInputStream類

package java.io;
// java.io包,通過數據流、序列化和文件系統提供系統輸入和輸出
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
// 導入一個包,這個包運用到了一個多線程的原子更新器

  public class BufferedInputStream extends FilterInputStream {
// 繼承fileinputstream,爲輸入流添加一些功能;使用他防止每次讀取時都得進行實際寫操作;代表“使用緩衝區”

private static int DEFAULT_BUFFER_SIZE = 8192;

  // 該變量定義了默認的緩衝大小 爲8192;

private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;

  // 最大長度依然是Integer.MAX_VALUE,並不是Integer.MAX_VALUE-8

protected volatile byte buf[];

  // 存儲數據的內部緩衝區數組,必要的時候可以用另外一個大小不同的數組替換它;
  // 注意volatile關鍵字表示不穩定變量,每次線程存取都應該直接從主程序中讀取
  // (作用於多線程環境中)防止主程序值改變,影響其中某個線程的值無法匹配對應而出錯;

private static final
    AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
    AtomicReferenceFieldUpdater.newUpdater
    (BufferedInputStream.class,  byte[].class, "buf");   

   // 緩存數組的一個原子更新器,該成員變量與buf數組的volatile關鍵字一起,實現buf數組的原子的更新;

protected int count;

   // 比緩衝區中最後一個有效字節的索引大 1 的索引。此值始終處於 0 到 buf.length 的範圍內;
   // 從 buf[0] 到 buf[count-1] 的元素包含從底層輸入流中獲取的緩衝輸入數據。

protected int pos;

  // pos = position ,緩衝區中的當前位置,這是將從buf數組中讀取的下一個字符的索引;
  // 此值始終處於 0 到 count 的範圍內。如果此值小於 count,則 buf[pos] 將作爲下一個輸入字節;
  // 如果此值等於 count,則下一次 read 或 skip 操作需要從包含的輸入流中讀取更多的字節。
  

protected int markpos = -1;

  // 最後一次調用 mark 方法時 pos 字段的值爲 -1; markpos的值始終處於 -1 到 pos 的範圍內,
  // 如果輸入流中沒有被標記的位置,則此字段爲 -1;如果輸入流中有被標記的位置,則 buf[markpos] 將用作 reset
  // 操作後的第一個輸入字節。如果 markpos 不是 -1,則從位置 buf[markpos] 到 buf[pos-1] 之間的
  // 所有字節都必須保留在緩衝區數組中(儘管對 count、pos 和 markpos 的值進行適當調整後,這些字節可能移動到
  // 緩衝區數組中的其他位置);除非 pos 與 markpos 的差超過 marklimit,否則不能將其丟棄。

protected int marklimit;

  // 調用 mark 方法後,在後續調用 reset 方法失敗之前所允許的最大提前讀取量。
  // 只要 pos 與 markpos 之差超過 marklimit,就可以通過將 markpos 設置爲 -1 來刪除該標記。

private InputStream getInIfOpen() throws IOException {
    InputStream input = in;
    if (input == null)
        throw new IOException("Stream closed");
    return input;
}

  // 如果輸入流爲 null ,則拋出傳輸流關閉“stream closed”的異常
  // 如果輸入流不爲 null ,則返回輸入流,並將數據存儲於 input 中

private byte[] getBufIfOpen() throws IOException {
    byte[] buffer = buf;
    if (buffer == null)
        throw new IOException("Stream closed");
    return buffer;
}

  // 創建一個輸入流數組,用來保存其參數;當輸入保存的參數數組爲 null 時,拋出“stream closed”異常,
  // 當不爲 null 時,直接返回數組 buffer ,並把輸入流存儲在數組之中;

public BufferedInputStream(InputStream in) {
    this(in, DEFAULT_BUFFER_SIZE);           // java中,用this引用當前對象;
}

  // 創建一個緩衝輸入流 BufferedInputStream 並保存其數據,即輸入流 in ,以便將來使用;
  // 回調緩衝輸入流,並且保存其默認參數(緩衝輸入流的長度);

public BufferedInputStream(InputStream in, int size) {
    super(in);  // java類中使用super引用父類成分,InputStream是BufferedInputSream的父類;
    if (size <= 0) {
        throw new IllegalArgumentException("Buffer size <= 0");

    buf = new byte[size];
}

  // 創建具有指定緩衝區大小的 BufferedInputStream 並保存其參數,即輸入流 in,
  // 以便將來使用。創建一個長度爲 size 的內部緩衝區數組並將其存儲在 buf 中。

private void fill() throws IOException {
    byte[] buffer = getBufIfOpen();
    if (markpos < 0)
        pos = 0;                        // 沒有標記,總是指向緩衝流的初始位置;
    else if (pos >= buffer.length)      // 位置比緩衝區長度大,緩衝區中沒有空間了;
        if (markpos > 0) {              // 拋出緩衝區的前半部分;
            int sz = pos - markpos;     // 字符串數據的長度;
            System.arraycopy(buffer, markpos, buffer, 0, sz);
            pos = sz;
            markpos = 0;                // 進行復制和初始化 pos 和 markpos;
        } else if (buffer.length >= marklimit) {
            markpos = -1;                // 緩衝區太大了,是一個無效的標誌位,返回-1;
            pos = 0;                     // 降低緩衝區的內容;
        } else if (buffer.length >= MAX_BUFFER_SIZE) {
            throw new OutOfMemoryError("Required array size too large");
        } else {                        // 緩衝區進行拓展
            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)) {
                // 如果這裏是不同步的關閉,則不能進行替換; 
                // 注意:如果滿了則需要進行拓展變換
                // 對於多線程來說,永遠不能達到
                // 唯一的方式是通過關閉來結束
                // 插入 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;    // 數量
}



public synchronized int read() throws IOException {
    if (pos >= count) {
        fill();           // 如果位置的值 pos 大於等於 長度數量 count;則調用fill()方法
        if (pos >= count)
            return -1;
    }
    return getBufIfOpen()[pos++] & 0xff;
}

    // 將字符串讀入到數組 array 之中,如果需要,最多進行 1 次;
private int read1(byte[] b, int off, int len) throws IOException {
int avail = count - pos;
if (avail <= 0) {
       // 如果請求的長度至少和緩衝器一樣的大,並且沒有進行 mark/reset 操作;
       // 不要急於拷貝不要急於拷貝字節到本地緩衝器之中,如果這樣,緩衝流將會無害級聯;
if (len >= getBufIfOpen().length && markpos < 0) {
return getInIfOpen().read(b, off, len);
}
fill();
avail = count - pos;
if (avail <= 0) return -1;
}
int cnt = (avail < len) ? avail : len;
System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
pos += cnt;
return cnt;
}

   // 以所給的偏移量開始,從輸入字節流中,讀取到具體字節流數組中;
public synchronized int read(byte b[], int off, int len)
throws IOException
{
getBufIfOpen(); // 檢查緩衝流是否關閉;
if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}

    int n = 0;
    for (;;) {
        int nread = read1(b, off + n, len - n);   // 讀入
        if (nread <= 0)
            return (n == 0) ? nread : n;    // 簡單的一個選擇語句,當n==0返回nread,否則返回n;
        n += nread;
        if (n >= len)
            return n;
        // 如果輸入流沒有關閉,但是,已經沒有字節可用,則直接返回;
        InputStream input = in;
        if (input != null && input.available() <= 0)
            return n;
    }
}




public synchronized long skip(long n) throws IOException {   // n爲跳過字節數;
    getBufIfOpen();    // 檢查字符流是否關閉
    if (n <= 0) {
        return 0;
    }
    long avail = count - pos;    //確定可用長度

    if (avail <= 0) {
        // 如果沒有設定標誌位置,也沒有保存在 buffer 緩衝器中;
        if (markpos <0)
            return getInIfOpen().skip(n);

        // 填滿 buffer 緩衝器,用以保存字節,等待重新設置;
        fill();
        avail = count - pos;
        if (avail <= 0)
            return 0;
    }

    long skipped = (avail < n) ? avail : n;  // 選擇判斷語句,跳過 avail 長度,或者跳過 n 長度;
    pos += skipped;
    return skipped;
}



//返回可以從該輸入流中讀取(或跳過)的字節數的估計數,而不需要對該輸入流的方法的下一次調用進行阻塞。
//下一個調用可能是同一個線程或另一個線程。此多字節的單個讀或跳過不會阻塞,但可能讀取或跳過更少字節。
public synchronized int available() throws IOException {
    int n = count - pos;
    int avail = getInIfOpen().available();
    return n > (Integer.MAX_VALUE - avail)
                ? Integer.MAX_VALUE
                : n + avail;
}


public synchronized void mark(int readlimit) {
    marklimit = readlimit;
    markpos = pos;
}


  // reset()重置方法;
public synchronized void reset() throws IOException {
    getBufIfOpen();     // 如果緩衝流關閉會拋出異常;
    if (markpos < 0)    // 標誌位置小於 0 ,會拋出異常;
        throw new IOException("Resetting to invalid mark");
    pos = markpos;
}



public boolean markSupported() {
    return true;    // 測試該輸入流支持位置標誌;
}

  // 關閉此輸入流並釋放與流相關聯的任何系統資源;
   // 一旦流已經關閉,進一步read(),available(),reset(),或skip()調用會拋出IOException;
   // 關閉先前關閉的流沒有效果。
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;
}
//其他的情況下,一個新的緩衝區被重新裝入,調用fill()方法;
}
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章