Java(四 ·下)通過源代碼學習NIO中的一個接口、兩個抽象類

Java(四 ·上)簡單說明一下NIO的基本概念
Java(四 ·下)通過源代碼學習NIO中的一個接口、兩個抽象類

重要的一個接口和兩個抽象類

在NIO中,有一個接口和兩個抽象類是我們需要重點了解的,ChannelBufferSelector

1.Channel

Channel跟stream差不多,但是Channel是雙向的(可以通過transferTo()或transferFrom()來改變數據的流向)

接口源碼

public interface Channel extends Closeable {
	//Channel接口只有兩個抽象方法
	//需要實現功能:檢查是否開啓
    public boolean isOpen();
    //需要實現功能:關閉通道
    public void close() throws IOException;

}

主要抽象類

這幾個類依然是沒有實現,它們的實現都是類名後加上Impl,如果想深入研究的話,就去看實現類吧,我這裏就只簡單說明一下它們的抽象類

  1. FileChannel
    這個就是文件通道了,上面的代碼中也有使用到,創建方式就不多說了。它的主要功能就是與文件進行數據傳輸
  2. DatagramChannel
    Datagram就是數據報的意思,學過網絡編程的應該都知道,數據報通道就是可以通過UDP在網絡上讀取和寫入數據,它的創建方法:
DatagramChannel ch = DatagramChannel.open();
  1. SocketChannel
    Socket就是套接字,套接字通道可以通過TCP在網絡上讀取和寫入數據,它的創建方法:
SocketChannel ch = SocketChannel.open(); 
//使用它還需要綁定一個ip地址
  1. ServerSocketChannel
    ServerSocketChannel是服務器套接字通道能夠監聽TCP的連接,在註冊到selector後,當selector的迭代器遍歷到相應的ServerSocketChannel時,它會根據SelectionKey獲取到ServerSocketChannel創建的SocketChannel,然後進行操作

2.Buffer

Buffer就是在進行NIO時開闢緩衝區的對象

抽象類源碼

內容太多了,簡單易懂的我就跳過了

public abstract class Buffer {
    static final int SPLITERATOR_CHARACTERISTICS =
        Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
	// Invariants: mark <= position <= limit <= capacity
	//這四個數是整個Buffer的關鍵
    private int mark = -1;//標記,可以通過這個標記回溯到標記的位置
    private int position = 0;//當前位置,讀和寫的操作都是從這個位置開始的
    private int limit;//界限,讀和寫都不能超過這個界限
    private int capacity;//容量,能夠寫入的個數,以具體實現類爲準,例如IntBuffer,最大就能寫capacity個int
    long address;//地址,這是指向緩衝區的地址

    Buffer(int mark, int pos, int lim, int cap) {       
        if (cap < 0)
            throw new IllegalArgumentException("Negative capacity: " + cap);
        this.capacity = cap;
        limit(lim);
        position(pos);
        if (mark >= 0) {
            if (mark > pos)
                throw new IllegalArgumentException("mark > position: ("+ mark + " > " + pos + ")");
            this.mark = mark;
        }
    }
    public final int capacity() {
        return capacity;
    }
    public final int position() {
        return position;
    }
    //這是重新定義position,如果大於limit或小於0則報錯
    //如果mark大於新的position,則丟去mark
    public final Buffer position(int newPosition) {
        if ((newPosition > limit) || (newPosition < 0))
            throw new IllegalArgumentException();
        position = newPosition;
        if (mark > position) mark = -1;
        return this;
    }
    public final int limit() {
        return limit;
    }
    //重新定義limit,如果limit大於capacity或小於0,則報錯
    //如果position大於新的limit,則重新定位到limit
    //如果mark大於新的limit,則丟棄
    public final Buffer limit(int newLimit) {
        if ((newLimit > capacity) || (newLimit < 0))
            throw new IllegalArgumentException();
        limit = newLimit;
        if (position > limit) position = limit;
        if (mark > limit) mark = -1;
        return this;
    }
    public final Buffer mark() {
        mark = position;
        return this;
    }
    //將position重新定位到mark上
    public final Buffer reset() {
        int m = mark;
        if (m < 0)
            throw new InvalidMarkException();
        position = m;
        return this;
    }
    //俗稱的切換到寫模式
    public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }
    //俗稱的切換到讀模式
    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }
    //這個也可以用來切換到讀模式,但是沒有修改limit
    public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }
    public final int remaining() {
        return limit - position;
    }
    public final boolean hasRemaining() {
        return position < limit;
    }
    //需要實現的功能:
    //返回這個buffer是否只可讀
    public abstract boolean isReadOnly();
    //需要實現的功能:
    //返回這個buffer的緩衝區,是否是一個可讀的數組構成的
    public abstract boolean hasArray();
    //需要實現的功能:
    //如果這個buffer緩衝區的數組不是隻可讀,就返回一個數組
    public abstract Object array();
    //需要實現的功能:
    //如果這個buffer緩衝區的數組不是隻可讀,返回數組的地址
    public abstract int arrayOffset();
    //需要實現的功能:
    //判斷緩衝區是否是直接緩衝區,也就是是否存儲在物理內存中,而不是存儲在JVM中
    public abstract boolean isDirect();
    final int nextGetIndex() {                          
        if (position >= limit)
            throw new BufferUnderflowException();
        return position++;
    }
    //將position後移nb個
    final int nextGetIndex(int nb) {                    
        if (limit - position < nb)
            throw new BufferUnderflowException();
        int p = position;
        position += nb;
        return p;
    }
    //僅是拋出的異常不同
    //上面是下溢異常,下面是上溢異常
    final int nextPutIndex() {                         
        if (position >= limit)
            throw new BufferOverflowException();
        return position++;
    }
    final int nextPutIndex(int nb) {                    
        if (limit - position < nb)
            throw new BufferOverflowException();
        int p = position;
        position += nb;
        return p;
    }
    //檢查是否能夠將position定位到i上
    final int checkIndex(int i) {                       
        if ((i < 0) || (i >= limit))
            throw new IndexOutOfBoundsException();
        return i;
    }
    //檢查是否能夠將position定位到i+nb上
    final int checkIndex(int i, int nb) {              
        if ((i < 0) || (nb > limit - i))
            throw new IndexOutOfBoundsException();
        return i;
    }
    final int markValue() {                            
        return mark;
    }
    //清空
    final void truncate() {                            
        mark = -1;
        position = 0;
        limit = 0;
        capacity = 0;
    }
    final void discardMark() {                         
        mark = -1;
    }
    //檢查開始位置,長度,尺寸是否符合條件
    static void checkBounds(int off, int len, int size) { // package-private
        if ((off | len | (off + len) | (size - (off + len))) < 0)
            throw new IndexOutOfBoundsException();
    }

}

主要抽象類

主要的抽象類有七個,ByteBuffer、CharBuffe、DoubleBuffer、FloatBuffer、 IntBuffer、 LongBuffer、 ShortBuffer
分別對應基本數據類型: byte, char, double, float, int, long, short。
它們也都是沒有實現的,它們的實現類就更加多樣化了,這裏就不展開講述了,功能基本上都是差不多的,只是對應的數據類型不一樣

3.Selector

Selector被稱爲選擇器,也被稱爲多路複用器,是整個NIO中最核心的組件(個人覺得,不適用Selector就沒有必要使用NIO了)
Channel能夠通過register()把自己註冊到Selector中並設置一個SelectionKey,然後Selector根據SelectionKey的迭代器不斷的循環,當有符合某個key時,就可以進行操作了,操作時根據SelectionKey就可以獲取到對應的Channel了。

selector
channel
channel
channel
channel

抽象類源碼


public abstract class Selector implements Closeable {
    protected Selector() { }
    //這是通過SelectorProvider的內部靜態對象provider創建一個Selector的實現類實例
    //最後的實例對象是WindowsSelectorImpl的實例
    public static Selector open() throws IOException {
        return SelectorProvider.provider().openSelector();
    }
    public abstract boolean isOpen();
	//需要實現的功能:
	//返回一個通道的創建者
    public abstract SelectorProvider provider();
    //需要實現的功能:
	//返回選擇器的鍵集,該鍵集不能被修改
    public abstract Set<SelectionKey> keys();
    //需要實現的功能:
	//返回選擇器的鍵集,該鍵集可以被修改
    public abstract Set<SelectionKey> selectedKeys();
	//需要實現的功能:
	//開始監聽通道,如果沒有通道是已經準備好的,就返回0
    public abstract int selectNow() throws IOException;
	//需要實現的功能:
	//開始監聽通道,設置一個超時時間
    public abstract int select(long timeout)
        throws IOException;
	//需要實現的功能:
	//開始監聽通道
    public abstract int select() throws IOException;
    //需要實現的功能:
	//喚醒那些阻塞在select方法上的線程
	//在實現類WindowsSelectorImpl中,有一個線程數組,應該是喚醒這個數組中的線程
    public abstract Selector wakeup();
    public abstract void close() throws IOException;

}

最終的實現類是WindowsSelectorImpl

——————————————————————————————
如果本文章內容有問題,請直接評論或者私信我。
未經允許,不得轉載!

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