Netty 是如何工作的?
因爲代碼中沒有異步的代碼。那非阻塞是如何實現的?
一個 NIO 是不是只能有一個 selector ?
可以有多個 selector
selector 是不是隻能註冊一個 ServerSocketChannel?
可以註冊多個
- 目錄結構
初始化服務
Start
//初始化線程
NioSelectorRunnablePool nioSelectorRunnablePool = new NioSelectorRunnablePool(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
//獲取服務類
ServerBootstrap bootstrap = new ServerBootstrap(nioSelectorRunnablePool);
//綁定端口
//初始化 Channel
//線程池 獲取 boss select
//selverChanner 註冊到 selector , key 爲 accept 狀態
bootstrap.bind(new InetSocketAddress(10101));
System.out.println("start");
-
init 線程池
boss 線程池
woker 線程池
每個線程一個 selector -
selector implements Runnable
1個selector 有 1個Queue taskQueue
每個 selector 都公用 boss pool or worker pool -
每一個 selector 獲取 Selector 並啓動線程 ,在 AbstractNioSelector 中執行 run 方法。
/**
* 獲取selector並啓動線程
*/
private void openSelector() {
try {
this.selector = Selector.open();
} catch (IOException e) {
throw new RuntimeException("Failed to create a selector.");
}
executor.execute(this);
}
run :
while (true) {
try {
wakenUp.set(false);
select(selector);
processTaskQueue();
process(selector);
} catch (Exception e) {
// ignore
}
}
Boss or Worker 註冊不同 Selector 的特有接口
public interface Boss {
/**
* 加入一個新的ServerSocket
* @param serverChannel
*/
public void registerAcceptChannelTask(ServerSocketChannel serverChannel);
}
NioSelectorRunnablePool
/**
* boss線程數組
*/
private final AtomicInteger bossIndex = new AtomicInteger();
private Boss[] bosses;
/**
* worker線程數組
*/
private final AtomicInteger workerIndex = new AtomicInteger();
private Worker[] workeres;
- 初始化線程池
- init boss 創建NIOServerBoss
private void initBoss(Executor boss, int count) {
this.bosses = new NioServerBoss[count];
for (int i = 0; i < bosses.length; i++) {
bosses[i] = new NioServerBoss(boss, "boss thread " + (i+1), this);
}
}
- initWorker 創建
private void initWorker(Executor worker, int count) {
this.workeres = new NioServerWorker[count];
for (int i = 0; i < workeres.length; i++) {
workeres[i] = new NioServerWorker(worker, "worker thread " + (i+1), this);
}
}
- 註冊並激活selector
當 boss 加入一個新的SeverSocket 時 //負責監聽端口 channel
當 worker channel 加入 selector 時 // 負責處理具體的 事件 channel
/**
* 註冊一個任務並激活selector
*
* @param task
*/
protected final void registerTask(Runnable task) {
taskQueue.add(task);
Selector selector = this.selector;
if (selector != null) {
//if wakeUp 是false那麼 update爲 true
//False return indicates that the actual value was not equal to the expected value.
if (wakenUp.compareAndSet(false, true)) {
selector.wakeup();//喚醒阻塞的 selector
}
} else {
taskQueue.remove(task);
}
}
ServerBootstrap
服務類,綁定端口
NioServerBoss
NioServerBoss extends AbstractNioSelector implements Boss
NioServerWorker
extends AbstractNioSelector implements Worker
AbstractNioSelector implements Runnable 最頂層的selector
- 初始化
- 每個線程都有 selector 的能力
AbstractNioSelector(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
this.executor = executor;
this.threadName = threadName;
this.selectorRunnablePool = selectorRunnablePool;
openSelector();
}
/**
* 獲取selector並啓動線程
*/
private void openSelector() {
try {
this.selector = Selector.open();
} catch (IOException e) {
throw new RuntimeException("Failed to create a selector.");
}
executor.execute(this);//執行當前線程對象,運行下面的 run方法
}
- 核心!!!!!!!
@Override
public void run() {
Thread.currentThread().setName(this.threadName);
while (true) {
try {
//設置select 阻塞狀態,當 registerTask 方法執行時醒來,處理。
wakenUp.set(false);
//抽象方法
//boss 選擇阻塞 自定義
//worker 選擇阻塞500ms 自定義
select(selector);
//執行任務隊列中 Runnable 對象的run ,註冊 channel到 boss or worker 等待處理的對象。
processTaskQueue();
//處理 selector
//boss 非阻塞接收事件,然後 register 到 worker 的隊列。
//worker 具體處理事件,與返回事件
process(selector);
} catch (Exception e) {
// ignore
}
}
}
boss | worker |
---|---|
- 註冊一個任務並激活selector
/**
* 註冊一個任務並激活selector
*
* @param task
*/
protected final void registerTask(Runnable task) {
taskQueue.add(task);
Selector selector = this.selector;
if (selector != null) {
//if wakeUp 是false那麼 update爲 true
//False return indicates that the actual value was not equal to the expected value.
if (wakenUp.compareAndSet(false, true)) {
selector.wakeup();//喚醒阻塞的 selector
}
} else {
taskQueue.remove(task);
}
}
存在疑問?
NIO 如何提高的效率?
如何多路複用?
見下次。