1. 程式人生 > >如何現實servlet的單執行緒模式

如何現實servlet的單執行緒模式

 這個面試題挺經典的,可是網上很多朋友的回答題不達意,所以我在這裡就這個問題做一下探討。

          網上朋友的回答是加入<%@ page isThreadSafe=”false”%>這條命令。天啊,我暈!這是什麼命令?是jsp的命令啊,怎麼會加入到servlet中呢?當然了,jsp的執行實質是servlet機制,這條命令是jsp頁面告訴容器編譯“我”的時候實現單執行緒。那我們看看他編譯後的servlet類和以前的servlet有什麼不同?沒有加入這條指令的頁面中servlet類定義是:

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {

………………………………//內部實現咱們大可以不看他。
}

而加入這個命令之後的類定義是:

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 SingleThreadModel {

…………………………//同樣省略實現細節

}

        我想大家應該很清楚的發現:加入<@page isThreadSafe="false">之後servlet是實現了SingleThreadModel介面的。有興趣的朋友可以查下相關資料,其實這個介面在servlet2.4之後就廢除了。那麼為什麼廢除?實現了這個介面檢視程式碼內容的時候卻發現什麼方法都沒新增,為什麼?

       其實這個介面只是一個標識,讓容器改變servlet生成策略的。

  預設的,servlet容器是隻建立servlet単例項,為請求提供執行緒池,我們為了能保證servlet的執行緒安全問題而不在servlet中新增例項屬性。

       但是如果一個servlet實現了SingleThreadModel介面那容器在建立例項池,為每個求情分配例項,當用戶請求結束時將例項歸還例項池。

       這樣做真的安全嗎?非也!因為每個請求都會分發一個servlet例項,對於同用戶下分發的不同的servlet來說很可能用到同一個session中的屬性資料,這樣當然出現了執行緒同步的問題,是不安全的!而且不同使用者也可能享用同一個context中的資料,也是不安全的。於是在servlet2.4中建議不再使用這樣的設定。

  這樣一來我們知道:如果非要實現servlet單執行緒那就要在servlet中實現SingleThreadModel介面,在jsp中新增<@ page isThreadSafe="false">命令。但是這是不被提倡的。

  也有網友疑問:讓servlet單執行緒而多例項本來不是為了執行緒安全的嗎?為什麼<@ page isThreadSafe=?>?的答案卻是false?

  我覺得這是個誤區,這樣設定真的是單執行緒嗎?那肯定不是了,其實這個設定只是要容器保證同一時刻只有一個執行緒能在servlet的service方法中執行,因為預設的容器例項化servlet時時単例項,如果同時只有一個執行緒去管理這個唯一的servlet例項,那效能將是極其慢的,為了解決這個問題,容器採取了servlet例項池的方式。每個請求一個執行緒,而一個執行緒一個servlet。

         因為這種方式並不是執行緒安全的,所以答案是false。

  終上所述:其實這道題目是指如果讓一個servlet例項對應一個執行緒,而不是一個servlet例項對應多個執行緒的預設方式。