1. 程式人生 > >多執行緒與單例物件之間的關係

多執行緒與單例物件之間的關係

在我在考慮考慮他們的時候思考了以下幾個問題:

1、我們通常都將dao層(資料庫連線層)設定成單例,這樣的話如果每次處理資料庫中的資料都需要同一個物件去處理的話,處理資料的效能完全得不到保證。

2、ssh中為什麼struts2中的action層必須建立多例?而ssm中springmvc的Controller層不需要建立多例?

3、一個單例模式建立的物件是可以同時被多個執行緒處理的,如果一個物件被多個執行緒同時處理的話,很有可能出現執行緒同步問題(關於執行緒中的安全問題,對物件加鎖請參考:http://lavasoft.blog.51cto.com/62575/99155/),如果兩個執行緒同時訪問一個函式的話,要不要加鎖呢,加鎖怎麼加,不加又怎樣?

理解思路:

  我們知道一個物件是可以同時被多個執行緒進行呼叫的,一個單例物件每次都只能有一個執行緒進行呼叫的話,就不會出現執行緒中的安全問題了。只有一個當一個物件加鎖後,才能做到每次只能有一個執行緒進行處理。

  多個執行緒處理一個物件的過程是怎麼樣的呢?每次建立一個執行緒,jvm虛擬機器就會在記憶體中給每個執行緒分配獨立的堆疊儲存空間。

  單例模式建立的物件在記憶體中是如何載入的呢?所有的單例模式的物件都是通過靜態方法獲取的,也就是說,每個單例模式的物件都是儲存在靜態共享區中!

  一個普通物件在一個執行緒中是怎麼載入的呢?
  這裡寫圖片描述

在一個執行緒中,如果建立一個物件,會先在堆記憶體中開闢一個儲存空間,該物件在建立的時候就會在棧記憶體中開闢空間,呼叫其構造方法、靜態程式碼塊等…當方法結束,會在棧記憶體中清除。一個執行緒在呼叫這個物件的方法的時候會在棧記憶體中建立一個空間儲存物件方法。

  同理,對於在一個執行緒載入單例模式物件的時候,它會在靜態共享區獲取單例物件,然後在呼叫物件方法(非靜態)的時候會在自己的棧記憶體開闢一個空間,所以每個執行緒在呼叫同一個物件的方法的時候都會在它的棧記憶體中開闢一個獨立的記憶體空間。這說明了多執行緒處理同一個物件的時候如果不涉及到物件的共有屬性值,不會存線上程安全問題。

  現在對文章開頭的內容進行一點解釋:

1、我們通常都將dao層(資料庫連線層)設定成單例,這樣的話如果每次處理資料庫中的資料都需要同一個物件去處理的話,處理資料的效能完全得不到保證。

  答:因為我們每次處理資料庫是使用session進行資料庫的互動處理,而session是由SessionFactory建立的,SessionFactory將創建出的session放入session連線池中,連線池中的session均為不同的物件。我們指的建立單例物件在這裡指的是SessionFactory。

2、ssh中為什麼struts2中的action層必須建立多例?而ssm中springmvc的Controller層不需要建立多例?

  答:struts2中因為將前端獲取的值全部都儲存在物件屬性中,所以肯定需要設定為多例,springMVC中,前端獲取的值直接進入方法中,所以設定為單例模式不會存線上程安全問題。

3、一個單例模式建立的物件是可以同時被多個執行緒處理的,如果一個物件被多個執行緒同時處理的話,很有可能出現執行緒同步問題(關於執行緒中的安全問題,對物件加鎖請參考:http://lavasoft.blog.51cto.com/62575/99155/),如果兩個執行緒同時訪問一個函式的話,要不要加鎖呢,加鎖怎麼加,不加又怎樣?

  答:一個單例模式的方法可以同時被多個執行緒處理,多個執行緒如果不是同時處理一個物件的共有屬性,則不會出現執行緒問題,即使是方法中的屬性如果兩個執行緒同時訪問同一個方法的時候,如果這個方法中沒有共有的屬性,則不需要加鎖,反之則需要加鎖。