EventLoopGroup : 事件循環組
EventLoop:事件循環
- 1個EventLoopGroup中包含1個或多個EventLoop
- 1個EventLoop在它的整個生命週期當中只會與唯一一個Thread進行綁定
- 所有由EventLoop所處理的各種I/O事件都將在它關聯的那個Thread上進行處理。
- 一個Channel在它的整個生命週期中只會註冊在一個EventLoop上。
- 一個EventLoop在運行過程當中,會被分配給一個或多個Channel。
總結:絕對不要在handler中做任何耗時的工作,一旦發生就會將EventLoop中的線程給卡在耗時的事件上,這樣其他許多channel的I/O事件都會等待,
解決辦法:在handler中啓動一個線程池
PS:當你去執行Channel上的任何一個操作時,netty一定會首先去判斷執行這個操作的線程是否就是Channel所對應的EventLoop所包含的線程,如果是則直接執行,否則netty以一個任務的形式提交給EventLoop,最終執行這個任務的線程還是EventLoop中的線程,通過這樣精巧的設計,netty在整個channel的操作上消除了所有的需要同步的地方。
重要結論:在Netty中,channel的實現一定是線程安全的,基於此,我們可以存儲一個channel的引用,並且在需要向遠程端點發送數據時,通過這個引用來調用channel相應的方法;即便當時有很多線程都在使用它也不會出現多線程問題;而且,消息一定會按照順序發送出去。
重要結論2:我們在業務開發中,不要將長時間執行的耗時任務放入到EventLoop的執行隊列中,因爲它將會一直阻塞該線程對應的所有channel上的其他執行任務,如果我們需要執行阻塞調用或是耗時的操作(開發中常見),那麼我們就需要使用一個專門的EventExecutor(業務線程池)。
:EventExecutor的兩種實現方式
1. 在ChannelHandler的回調方法中,使用自己定義的業務線程池,這樣就可以實現異步調用
2.藉助netty提供的向ChannelPipeline添加ChannelHandler時調用addLast方法來傳遞EventExecutor.
說明:默認情況下(調用addLast(handler)),channelHandler中的回調發放都是由I/O線程所執行,如果調用了ChannelPipeline addLast(EventExecutorGroup group,ChannelHandler .. handlers)方法,那麼ChannelHandler中的回調方法就是由參數中的group線程組來執行的。