目的
爲了保證客戶端的請求是順序發送到服務端的,ctx.writeAndFlush被包裝在用synchronized修飾的send方法中,客戶端統一調用sendRequest方法。
有多個線程使用sendRequest方法
1.eventLoop處理channelRead的結果,並調用sendRequest發送到服務端。
2.業務線程(如心跳線程,http請求對應的線程)去調用ctx.writeAndFlush
造成的後果
從客戶端看日誌是順序的,但是服務端總是收到非連續的請求。
代碼
服務端
檢測客戶端的請求cmdCnt,如果小於當前服務端的值,那麼就認爲是過期的命令
客戶端
同步的sendRequest方法,保證不同線程都是順序執行,cmdCnt順序增長。
除了EventLoop線程,業務線程也會調用到sendRequest
EventLoop線程執行sendRequest
原因
這是EventLoop的一個特性:【非EventLoop線程】調用ctx.writeAndFlush時,不會直接執行,而是放入taskQueue隊列中(等待之後eventLoop線程去執行)。
解決方法
全部改爲非業務線程去執行同步的sendRequest方法,去執行ctx.writeAndFlush,最終都提交給隊列。那麼順序提交到隊列,就順序取出發送到服務端。避免了EventLoop線程直接執行writeAndFlush。
解決問題的代碼
注意,內部的sendRequest纔是同步方法。
EventLoop處理任務流程