Netty 02 | 源碼分析

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");
  1. init 線程池
    boss 線程池
    woker 線程池
    每個線程一個 selector

  2. selector implements Runnable
    1個selector 有 1個Queue taskQueue
    每個 selector 都公用 boss pool or worker pool

  3. 每一個 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;
  1. 初始化線程池
  2. 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);
		}
	}
  1. 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);
		}
	}
  1. 註冊並激活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 如何提高的效率?
如何多路複用?
見下次。

源碼DEMO

https://github.com/GggggitHub/Netty01

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