前言
曾經有兩個人,一個是A,一個是B,他們倆都是這個世界上獨立的個體,每個人都是這個世界上獨一無二的。這個A呢,在一出生的時候,别人就會把他需要的食物全部給他,然後等到他餓了的時候,就可以直接拿過來吃,但是在他不餓的時候,天天被在身上确是一種負擔,人們都管他叫做餓漢。B呢,則是在出生的時候,并沒有任何食物給他,但是在他餓的時候,他連伸手都不用,隻需要張嘴喊一嗓子,便有人給他送來了食物,就因為他這麼懶,是以被叫做懶漢。為什麼要講這個故事呢,接下來你就會明白了。
單例模式
在web開發中,我們經常碰到這樣一種情況,我們在整個項目的上下文中,有且隻有一個執行個體,所有線程操縱的都是它,例如說Mybatis中的SqlSessionFactory。如果說隻存在一個執行個體,那麼他絕對是不可以new出來,是以他的構造方法一定是私有的。
單例模式從方式上分為懶漢模式,和餓漢模式,這就像是咱們剛剛提到故事裡的B和A一樣,具體代碼如下:
package singleton;
/**
* 這是懶漢模式,但是對于多線程的情況下是不安全的
*
* @author luckyharry
*
*/
public class SingletonLazyNotSafe {
private SingletonLazyNotSafe() {
System.out.println("單例懶漢模式,無鎖,執行個體化--");
}
private static SingletonLazyNotSafe singletonLazyNotSafe;
public static SingletonLazyNotSafe getInstance() {
if (singletonLazyNotSafe == null) {
singletonLazyNotSafe = new SingletonLazyNotSafe();
}
return singletonLazyNotSafe;
}
}
這是懶漢模式,但是我們會發現getInstance()方法,多個線程可能會共同競争,将會導緻資料的不統一性,那麼我們需要給它添加一個鎖,關鍵字synchronized。
package singleton;
/**
* 這是懶漢模式,對于多線程的情況下是安全的 但是因為加了鎖,是以效率比較低
*
* @author luckyharry
*
*/
public class SingletonLazySafe {
private SingletonLazySafe() {
System.out.println("懶漢模式 有鎖 執行個體化--");
}
private static SingletonLazySafe singletonLazySafe;
public static synchronized SingletonLazySafe getInstance() {
if (singletonLazySafe == null) {
singletonLazySafe = new SingletonLazySafe();
}
return singletonLazySafe;
}
}
懶漢模式,他是在當需要獲得的時候才執行個體化,就像是剛剛所說的B那個人一樣,實作了懶加載。但是加了鎖之後,效率比較低下。
package singleton;
public class SingletonHunger {
private static SingletonHunger singletonHunger=new SingletonHunger();
// 構造器為私有的,不可以通過new實力化
private SingletonHunger() {
System.out.println("初始化 Singleton 餓漢方式--");
}
public static SingletonHunger getInstance() {
return singletonHunger;
}
}
餓漢模式我們不再去考慮多線程的問題,但是它卻是在類加載的時候便會執行個體化單例本身,并未實作懶加載。這就像是剛剛說的A一樣,在一出生的時候,該執行個體化的已經被執行個體化放在那了。
package singleton;
public class SingletonInnerClass {
// 構造器為私有的,不可以通過new實力化
private SingletonInnerClass() {
System.out.println("初始化 Singleton 内部類方式--");
}
private static class SingletonCreate {
private static SingletonInnerClass singleton = new SingletonInnerClass();
}
public static SingletonInnerClass getInstance() {
return SingletonCreate.singleton;
}
}
這種内部類的形式,既解決了鎖的問題,又實作了懶加載,是一種懶漢模式的變種。
接下來就是測試類了。
package singleton;
/**
* 懶漢模式以及餓漢模式的本質差別在于
* 單例的類的初始化的位置,如果我們是在類剛開始初始化的時候就初始化了的化,那麼是餓漢加載
* 如果我們是在擷取執行個體的那個方法初始化的化(實作了懶加載),那就是懶漢模式。
* @author luckyharry
*
*/
public class MainTest {
public static void main(String[] args) {
//獲得單例中的執行個體
SingletonInnerClass.getInstance();
SingletonLazyNotSafe.getInstance();
SingletonLazySafe.getInstance();
SingletonHunger.getInstance();
}
}
後記
我會一直以這樣通俗易懂的自己能想到的例子,講解設計模式,最大的啟發是來源于《大話設計模式》。非常感覺這本書的作者程傑先生。