Netty之线程唤醒wakeup
首先回顧下, Netty中的IO線程主要完成三件事
1.輪詢IO事件
2.處理IO事件
3.執行任務
在輪詢IO事件的過程中,在Linux系統下, 使用epoll實現.
涉及的Netty代碼如下
當IO線程執行以上代碼的時候, 如果超時時間timeoutMillis還沒有到達的情況下, IO線程就會處于阻塞狀態. 這個時候如果非IO線程需要向對端寫數據, 由于Netty是異步的框架, 它的實現是非IO線程將寫數據封裝成一個任務提交到IO線程的任務隊列里.
當任務提交到任務隊列后, 那么就會面臨一個問題.此時的IO線程處于阻塞狀態, 是否需要喚醒它呢?
答案是需要喚醒, 之所以要把它喚醒, 是需要讓IO線程可以及時的處理剛剛非IO線程提交的任務.
以上代碼, 就是喚醒的代碼, 主要調用的方法就是wakeup.
接下來通過查看它的系統調用, 弄清楚它到底是如何實現的.
代碼如下
以上代碼的邏輯比較簡單, 一個線程調用select()方法阻塞, 另一個線程喚醒它.
首先javac編譯以上代碼, 然后使用一個查看系統調用的命令strace.
strace -ff -o strace java WakeUp
具體如何使用strace請童鞋自行Google
執行以后, 通過以下步驟進行分析
使用jps查看進程ID號
獲得PID=1141
進入 /proc/1141/fd目錄下, 就可以查看到當前進程(PID=1141)打開的文件描述符
0,1,2這三個文件描述符是標準輸入,標準輸出和錯誤輸出.
4號文件描述符是在使用epoll實現的多路復用IO創建的一個文件描述符.
5,6這兩個文件描述符是一對管道.
7是select創建的套接字
在上面執行strace命令的時候, 在它的同目錄下會生成如下文件
通過搜索strace命令打印的文件內容, 查看具體的系統調用方法.
使用grep命令搜索關鍵字pipe
程序調用pipe這個系統調用創建管道.
其中的5和6是兩個文件描述符,也就是在/proc/1141/fd目錄下的那兩個5和6文件描述符.
5這個描述符用來讀取數據, 6這個描述符用來寫入數據, 這樣就實現了兩個進程之間的通信.
epoll三個關鍵的方法: epoll_create,epoll_ctl,epoll_wait.
epoll_create用于創建epoll文件描述符
epoll_ctl用于管理其他文件描述符
epoll_wait用于阻塞等待其他文件描述符就緒.
使用grep命令搜索關鍵字epoll
通過epoll_create創建4號文件描述符.
5和7這兩個文件描述符添加到epoll上(底層是添加到內核的紅黑樹).
在上面的Java代碼中, 當調用int readyChannels = selector.select()方法的時候, 底層就會調用epoll_wait方法, 那么線程就會阻塞在此.
當另一個線程調用selector.wakeup()的時候, 它就會向6號文件描述符寫入數據, 通過pipe通信的方式, 喚醒另一個阻塞的線程.
可以通過grep搜索關鍵字write驗證結論.
通過write系統調用向6號文件描述符寫入數據, 具體數據沒有任何含義, 它就是想喚醒阻塞的線程. 與6號文件描述符對應的是5號文件描述符. 由于epoll管理著5號文件描述符, 這樣epoll發現有文件描述符就緒(5號文件描述符就緒), 被阻塞的線程也就會被操作系統重新調度.
以上簡單介紹了Netty中IO線程如何阻塞和被喚醒的底層系統調用.
個人站點
語雀
公眾號
總結
以上是生活随笔為你收集整理的Netty之线程唤醒wakeup的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一些免费的无限制接口
- 下一篇: 程序员表白程序,开放源码,不断更新