1:單例模式(面試)
單例模式:單一的例項.保證類在記憶體中只有一個物件.
舉例:
①windows的列印費服務.網站的計數器.(如果一個網站統計訪問量有多個計數器,就會有問題.)
②Java中的應用:資料庫連線池,Runtime這個類.
2.如何保證類在記憶體中只有一個物件?
A:把構造方法私有,為了不讓外界建立物件.
B:在類中建立 一個物件.(有一個物件,還是要建立它)
C:通過一個公共的訪問方式,給外界一個入口.(否則外界根本就無法訪問到)
3.餓漢式單例模式:
Student.java
1 public class Student { 2 //為了不讓外界訪問,我們把構造方法私有. 3 private Student(){ 4 5 } 6 //建立一個物件 7 //為了滿足靜態方法訪問,這裡也必須加一個靜態修飾符static(暫時先不加private,慢慢引入private) 8 //static Student s = new Student(); 9 private static Student s = new Student(); 10 11 //提供一個公共的訪問方式 12 //(訪問這個方法可以通過Student類的物件,但是構造方法私有化了無法讓外界訪問) 13 //所以為了讓外界直接訪問,只能讓這個方法靜態. 14 public static Student getStudent(){ 15 //比如說我有t1和t2同時來訪問,那麼這個時候.拿的都是上面new的 17 return s; 18 //如果此時上面的Student s = new Student();不用靜態修飾,報錯.內容如下 19 //Cannot make a static reference to the non-static field s 20 //一個靜態的上下文,不能有一個非靜態的變數. 21 //所以為了滿足靜態方法訪問,new Student的時候必須用static修飾. 22 } 23 24 public void show(){ 25 System.out.println("我愛java"); 26 } 27 }
測試類:StudentTest.java
1 public class StudentTest { 2 public static void main(String[] args) { 3 /* 4 Student s1 = new Student(); 5 Student s2 = new Student(); 6 System.out.println(s1 == s2);//false 7 */ 9 //由於成員變數是被靜態static修飾的,前面沒有加訪問修飾符,預設是default外界也可以通過類名訪問的. 10 //Student.s = null; 11 //這樣的話下面執行s1.show()的時候就會報java.lang.NullPointerException 12 //為了不讓外界訪問s,就再在new 的時用private修飾. 這樣此時 13 14 //通過單例模式獲取物件並呼叫方法. 15 16 Student s1 = Student.getStudent(); 17 Student s2 = Student.getStudent(); 18 System.out.println(s1 == s2);//true 19 20 s1.show(); 21 s2.show(); 22 } 23 }
4:懶漢式單例模式(想用的時候再用)
懶漢式有一個非常重要的思想----延遲載入思想.
我們什麼時候需要,你就什麼時候給. 這個思想在Hibernate和Spring中都用了這個思想. 特別是Hibernate框架中的lazy....
Teacher.java
1 public class Teacher { 2 // 為了不讓外界建立物件,把構造方法私有. 3 private Teacher() { 4 } 5 6 // 本類建立一個物件. 7 // 加static是為了保證靜態方法可以訪問. 8 // 加private是為了保證外界不能直接訪問 9 private static Teacher t = null; 10 11 // 提供公共的訪問方式. 12 //synchronized是為了解決懶漢式多執行緒不安全加上的. 13 //被同步的程式碼,在某一時刻只能被一個執行緒訪問. 14 public synchronized static Teacher getTeacher() { 15 /* 16 比如說我有t1和t2同時來訪問,那麼這個時候. 17 當t1進來後,判斷這個時候t是null 18 所以,t1就進去執行if所控制的語句. 19 但是注意了,由於執行緒的隨機性.可能當t1剛進去要執行if說控制的語句. 20 發現,這個時候t還是null,所以,t2也去執行if所控制的語句了. 21 那麼將來就會有多個物件被建立. 22 */ 23 // 當外界需要使用它,就在這裡new一個. 24 if (t == null) { 25 // 只有第一次訪問這裡的時候才進入if語句new一個物件. 26 // 第二次的時候因為第一次已經new了一個Teacher,並且Teacher是用static修飾 27 // static修飾的是共享的.有值了,就不再進入if了. 28 t = new Teacher(); 29 } 30 return t; 31 } 32 33 // 寫了一個方法 34 public void love() { 35 System.out.println("老師愛學生"); 36 } 37 }
TeacherTest.java
1 public class TeacherTest { 2 public static void main(String[] args) { 3 Teacher t1 = Teacher.getTeacher(); 4 Teacher t2 = Teacher.getTeacher(); 5 System.out.println(t1 == t2);// true 6 7 t1.love(); 8 t2.love(); 9 } 10 }
5:那麼我們在開發中到底使用誰呢?
一般開發中使用第一種方案(餓漢式)
原因是:
前提:多執行緒安全問題.
面試的時候會面試懶漢式. 並且,請注意,面試懶漢式,主要是面試下面幾個問題:
A:延遲載入思想.
B:執行緒安全問題.
a:執行緒安全問題是怎麼產生的.
b:執行緒安全問題是怎麼解決的.
6:其實在JDK中提供的類中,已經有單例模式的應用.是誰呢?Runtime類.
附上JDK中關於Runtime類的原始碼:
Runtime.java
1 public class Runtime { 2 //這就是一個餓漢式的應用. 3 private static Runtime currentRuntime = new Runtime(); 4 5 public static Runtime getRuntime() { 6 return currentRuntime; 7 } 8 9 private Runtime() {} 10 11 }