Java(四 ·上)簡單說明一下NIO的基本概念
Java(四 ·下)通過源代碼學習NIO中的一個接口、兩個抽象類
重要的一個接口和兩個抽象類
在NIO中,有一個接口和兩個抽象類是我們需要重點了解的,Channel,Buffer,Selector
1.Channel
Channel跟stream差不多,但是Channel是雙向的(可以通過transferTo()或transferFrom()來改變數據的流向)
接口源碼
public interface Channel extends Closeable {
//Channel接口只有兩個抽象方法
//需要實現功能:檢查是否開啓
public boolean isOpen();
//需要實現功能:關閉通道
public void close() throws IOException;
}
主要抽象類
這幾個類依然是沒有實現,它們的實現都是類名後加上Impl,如果想深入研究的話,就去看實現類吧,我這裏就只簡單說明一下它們的抽象類
- FileChannel
這個就是文件通道了,上面的代碼中也有使用到,創建方式就不多說了。它的主要功能就是與文件進行數據傳輸 - DatagramChannel
Datagram就是數據報的意思,學過網絡編程的應該都知道,數據報通道就是可以通過UDP在網絡上讀取和寫入數據,它的創建方法:
DatagramChannel ch = DatagramChannel.open();
- SocketChannel
Socket就是套接字,套接字通道可以通過TCP在網絡上讀取和寫入數據,它的創建方法:
SocketChannel ch = SocketChannel.open();
//使用它還需要綁定一個ip地址
- 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了。
抽象類源碼
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
——————————————————————————————
如果本文章內容有問題,請直接評論或者私信我。
未經允許,不得轉載!