在 mina簡介 中提到,mina 是一個多線程的框架,本文就來看看 mina 中線程的使用。mina 中都是使用 java.util.concurrent.Executor 來使用線程的。
注意: 本文中所討論的 mina 中的線程是針對基于 socket 的應用程序的,也就是說使用 SocketAcceptor 的程序,另外兩種 IoAcceptor 的實現中對線程的使用可能相同,也可能不同,我并沒有對它們做過多的研究。
在基于 SocketAcceptor 的應用程序中,運行過程中 mina 框架本身會有兩種類型的線程在運行,一種是在 SocketAcceptor 中創(chuàng)建的用于監(jiān)聽并接收來自客戶端請求的線程,還有一類線程是處理客戶端與服務器端 I/O 的線程。
當調用 SocketAcceptor 的 bind 方法時,默認會創(chuàng)建一個名稱前綴為 SocketAcceptor 的線程,該線程負責監(jiān)聽來自客戶端的請求,如果接收到客戶端的請求,它僅僅是為處理這個請求做好準備,而把具體處理請求以及 I/O 的任務代理給 SocketIoProcessor,讓它去處理請求。這個準備過程主要是為接受到的請求創(chuàng)建一個 IoSession,并構建出 IoFilter 鏈,然后把準備好的數據以及來自客戶端的請求交給 SocketIoProcessor 處理。通常 這類線程會針對每一次的 bind 調用創(chuàng)建一個新的線程。
請注意 前一節(jié)中的“通常 ” 二字,使用這兩個字說明上述的行為不是絕對的。的確這不是絕對的,這取決于 SocketAcceptor 的字段 executor 的實現,可以通過構造方法來設置字段 executor 的值,executor 字段的類型為 java.util.concurrent.Executor。mina 默認是用 org.apache.mina.util.NewThreadExecutor,它會為每一個提交的任務創(chuàng)建一個新的線程。因為在 bind 方法中它會把實現監(jiān)聽客戶端請求任務的 Runnable 提交到 executor 中去執(zhí)行。注意千萬不要使用一個不創(chuàng)建新線程而是在原線程中執(zhí)行的 Executor,這會使程序無法監(jiān)聽客戶端的請求,因為程序中的唯一線程會被 Selector.get() 方法所阻塞,詳情可以查看 SocketAcceptor 類的源代碼。
當 SocketAcceptor 收到了來自客戶端的請求,它就會把此請求丟給 SocketIoProcessor 去處理,這會創(chuàng)建名稱以 SocketAcceptorIoProcessor 為前綴的線程,mina 框架在這類線程中處理 I/O 發(fā)布并處理事件。這一類線程的數量可以通過 SocketAcceptor 的構造函數來設置。具體的值可以根據應用的具體需求來決定。
上述的兩類線程是 mina 框架本身所創(chuàng)建的,如果你的應用每次處理請求的時間較長而又希望應用能夠有較好的響應性,那么最好是把處理業(yè)務邏輯的任務放到一個新的線程中去執(zhí)行,而不是在 mina 框架創(chuàng)建的線程中去執(zhí)行。
mina 框架本身提供了一個過濾器 ExecutorFilter 來完成這樣的任務,它會把在此之后的過濾器以及 IoHandler 中處理業(yè)務邏輯的代碼放到一個新的線程中去執(zhí)行。當 mina 框架中的第二類線程執(zhí)行完此過濾器后就會立即返回,可以用于處理新的請求。如果不想使用此過濾器,還可以設置 mina 的線程模型來達到相同的效果,其實線程模型也是使用 ExecutorFilter 實現的。但需要注意的是,在 mina 2.0 版本中已經廢棄了線程模型。
mina 框架中具體的如何使用線程可以查看它的源代碼,本文只是一個簡單地介紹,在 mina 網站的文檔中也有一份針對 mina 1.x 版本中的線程模型的說明,請參見 http://mina./configuring-thread-model.html