readline()函數的阻塞機制最新版最全詳解


如果你也是年輕的程序員,關注我一起學習探討

最近在工作中遇到了一個Android的ANR問題,經過分析是WiFiStateMachine調用了系統函數readline(),然后出現了阻塞的現象,然后就深入了解了一下readline函數。網上搜了一下,發現關於readline()函數的解釋大都是說readline()函數是阻塞函數,沒有消息是並不會返回null,而是一直阻塞在那。至於阻塞的實質,都沒有涉及,我經過仔細分析源碼,得出結論如下:

我們先看readline函數源碼,其中fill()函數才是真正讀取數據的地方,只有讀取完成之后,才會執行下面“/n”“/r”的判斷,而讀取數據的時候為什么阻塞,之前並沒有人探究,那我們后面看看fill函數。

String readLine(boolean ignoreLF) throws IOException {
        StringBuffer s = null;
        int startChar;

        synchronized (lock) {
            ensureOpen();
            boolean omitLF = ignoreLF || skipLF;

        bufferLoop:
            for (;;) {

                if (nextChar >= nChars)
                    fill();  //真正讀取數據的地方
                if (nextChar >= nChars) { /* EOF */
                    if (s != null && s.length() > 0)
                        return s.toString();
                    else
                        return null;
                }
              ...........其他
              charLoop:
                for (i = nextChar; i < nChars; i++) {
                    c = cb[i];
                    if ((c == '\n') || (c == '\r')) {  //判斷是否遇到\n或者\r,如果遇到就結束,作為一行數據輸出。
                        eol = true;
                        break charLoop;
                    }
                }

fill()函數中,可以看到讀取數據是用了read(char[] cbuf, int off, int len) 來讀取數據,當沒有數據時,n值為0,while循環就不會結束,就會一直在此阻塞。

    private void fill() throws IOException {
        int dst;
        if (markedChar <= UNMARKED) {
            /* No mark */
            dst = 0;
        } else {
        ..............其他
        int n;
        do {
            n = in.read(cb, dst, cb.length - dst);
        } while (n == 0);   //阻塞的關鍵
        if (n > 0) {
            nChars = dst + n;
            nextChar = dst;
        }
    }

總結:
1、讀入的數據要注意有/r或/n或/r/n
2、沒有數據時會阻塞,在數據流異常或斷開時才會返回null
3、readline()函數不會邊讀邊輸出,而是有一個緩沖區,讀出的數據先放到緩沖區,遇到/r或/n或/r/n后再輸出。

源碼路徑:xref: /libcore/ojluni/src/main/java/java/io/BufferedReader.java


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM