###java最全單例模式
定義;
確定某一個類隻有一個執行個體,并且自行執行個體化并且向整個系統提供這個執行個體
實作單例模式有幾個比較重要的關鍵點:
- 構造的函數一般不對外進行開放,使用private私有屬性
- 通過一個靜态方法或者枚舉傳回單例對象
- 確定單例類的對象有且隻有一個,尤其是在多線程下,一定要保持線程的安全
- 確定單例類對象子反序列化的時候不會重新建構對象
單例模式分類:
- 餓漢式單例模式
- 懶漢式單例模式
- 雙重檢查鎖實作單例
- 靜态内部類來實作單例模式
- 使用枚舉類型來實作單例
- 使用容器的形式來實作單例子模式
餓漢式單例模式
在靜态代碼塊中去new對象, 但是線程不安全,在不使用的時候,其實對象也已經執行個體化了
package com.example.zzf.single;
import java.io.ObjectStreamException;
/**
* 餓漢式單例模式
* 在靜态代碼塊中去new對象,
* 但是線程不安全,在不使用的時候,其實對象也已經執行個體化了
* @author Administrator
*
*/
public class SingleTonOne {
private static final SingleTonOne singleTonOne = new SingleTonOne();
private SingleTonOne(){
}
public static SingleTonOne getInstance(){
return singleTonOne;
}
public void doSomething(){
System.out.println("this is SingleTonOne");
}
/**
* 防止單例對象在序列化後,再次反序列化後生成不同的對象
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return singleTonOne;
}
}
####懶漢式單例模式
優點:在執行個體化的時候去new對象,線程安全
缺點:每一次使用的時候都需要進行同步一次,這樣會過多的消耗資源
package com.example.zzf.single;
import java.io.ObjectStreamException;
/**
* 懶漢式單例模式
* 優點:在執行個體化的時候去new對象,線程安全
* 缺點:每一次使用的時候都需要進行同步一次,這樣會過多的消耗資源
* @author Administrator
*
*/
public class SingleTonTwo {
private static SingleTonTwo singleTonTwo;
private SingleTonTwo(){
}
public static synchronized SingleTonTwo getInstance(){
if(singleTonTwo == null){
singleTonTwo = new SingleTonTwo();
}
return singleTonTwo;
}
public void doSomething(){
System.out.println("this is SingleTonTwo");
}
/**
* 防止單例對象在序列化後,再次反序列化後生成不同的對象
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return singleTonTwo;
}
}
####雙重檢查鎖實作單例
優點:在需要的時候才去執行個體化,而且能保證線程的安全行,而且單例模式在初始化後,就不會在進行同步,也不會過多的消耗資源
缺點:第一次在加載的時候會加載稍微慢一點,雙重檢查鎖失效可能會出現單例實作有問題
package com.example.zzf.single;
import java.io.ObjectStreamException;
/**
* 雙重檢查鎖實作單例
* 有點:在需要的時候才去執行個體化,而且能保證線程的安全行,而且單例模式在初始化後,就不會在進行同步,也不會過多的消耗資源
* 缺點:第一次在加載的時候會加載稍微慢一點
* @author Administrator
*
*/
public class SingleTonThree {
private static SingleTonThree sInstance = null;
// private static volatile SingleTonThree sInstance = null; //從主記憶體中讀取,會影響性能
private SingleTonThree(){
}
public static SingleTonThree getInstance(){
if(sInstance == null){
synchronized (SingleTonThree.class) {
if(sInstance == null){
sInstance = new SingleTonThree();
}
return sInstance;
}
}
return sInstance;
}
public void doSomething(){
System.out.println("this is SingleTonThree");
}
/**
* 防止單例對象在序列化後,再次反序列化後生成不同的對象
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return sInstance;
}
}
靜态内部類來實作單例模式
由于雙重檢查鎖在高并發或者因為記憶體模型的原因,有時候偶爾會失效,是以推薦使用靜态内部類來實作單例模式
第一次加載的時候不會初始化SingleTonFour,隻有第一次調用getInstance的時候才會去建立對象,
既保證了線程安全性麼也保證對象唯一性,同時延遲了單例的執行個體化
package com.example.zzf.single;
import java.io.ObjectStreamException;
/**
* 靜态内部類來實作單例莫斯
* 由于雙重檢查鎖在高并發或者因為記憶體模型的原因,有時候偶爾會失效,是以推薦使用靜态内部類來實作單例模式
* 第一次加載的時候不會初始化SingleTonFour,隻有第一次調用getInstance的時候才會去建立對象,
* 既保證了線程安全性麼也保證對象唯一性,同僚延遲了單利的執行個體化
* @author Administrator
*
*/
public class SingleTonFour {
private SingleTonFour(){
}
public static SingleTonFour getInstance(){
return SingleTonFourHolder.singleTonFour;
}
private static class SingleTonFourHolder{
private static final SingleTonFour singleTonFour = new SingleTonFour();
}
public void doSomething(){
System.out.println("this is SingleTonFour");
}
/**
* 防止單例對象在序列化後,再次反序列化後生成不同的對象
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return SingleTonFourHolder.singleTonFour;
}
}
####使用枚舉類型來實作單例
好處:枚舉在java中就和普通的類型是一樣的,不僅能夠有字段,還可以有自己的方法,最主要的就是枚舉類型執行個體的建立預設是線程安全的,在任何一種情況下他都隻會有一個執行個體
package com.example.zzf.single;
/**
* 使用枚舉類型來實作單例
* 好處:枚舉在java中就和普通的類型是一樣的,不僅能夠有字段,還可以有自己的方法,最主要的就是枚舉類型執行個體的建立預設是線程安全的,在任何一種情況下他都隻會有一個執行個體
*
* @author Administrator
*
*/
public enum SingleTonEnum {
INSTANCE;
public void doSomething(){
System.out.println("this is SingleTonEnum!");
}
}
####使用容器的形式來實作單例子模式
将多個單例類型全部注入到一個管理類中進行統一管理,根據需求來選擇
package com.example.zzf.single;
/**
* 使用容器的形式來實作單例子模式
* 将多個單例類型全部注入到一個管理類中進行統一管理,根據需求來選擇
*
*/
import java.util.HashMap;
import java.util.Map;
public class SingleTonManager {
private static Map<String,Object> objectMap = new HashMap();
private SingleTonManager(){
}
public static void registerSingleServer(String key,Object instance){
if(!objectMap.containsKey(key)){
objectMap.put(key, instance);
}
}
public static Object getSingleService(String key){
return objectMap.get(key);
}
}
MainTest.java中的代碼:
package com.example.zzf;
import com.example.zzf.single.SingleTonEnum;
import com.example.zzf.single.SingleTonFour;
import com.example.zzf.single.SingleTonManager;
import com.example.zzf.single.SingleTonOne;
import com.example.zzf.single.SingleTonThree;
import com.example.zzf.single.SingleTonTwo;
public class MainTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
SingleTonOne singleTonOne = SingleTonOne.getInstance();
singleTonOne.doSomething();
SingleTonManager.registerSingleServer("SingleTonOne", singleTonOne);
SingleTonTwo singleTonTwo = SingleTonTwo.getInstance();
singleTonTwo.doSomething();
SingleTonManager.registerSingleServer("SingleTonTwo", singleTonTwo);
SingleTonThree singleTonThree = SingleTonThree.getInstance();
singleTonThree.doSomething();
SingleTonManager.registerSingleServer("SingleTonThree", singleTonThree);
SingleTonFour singleTonFour = SingleTonFour.getInstance();
singleTonFour.doSomething();
SingleTonManager.registerSingleServer("SingleTonFour", singleTonFour);
SingleTonEnum singleEnum = SingleTonEnum.INSTANCE;
singleEnum.doSomething();
SingleTonManager.registerSingleServer("SingleTonEnum", singleEnum);
System.out.println("===========================================");
singleTonOne = (SingleTonOne) (SingleTonManager.getSingleService("SingleTonOne"));
singleTonTwo = (SingleTonTwo) SingleTonManager.getSingleService("SingleTonTwo");
singleTonThree = (SingleTonThree) SingleTonManager.getSingleService("SingleTonThree");
singleTonFour = (SingleTonFour) SingleTonManager.getSingleService("SingleTonFour");
singleEnum = (SingleTonEnum) SingleTonManager.getSingleService("SingleTonEnum");
singleTonOne.doSomething();
singleTonTwo.doSomething();
singleTonThree.doSomething();
singleTonFour.doSomething();
singleEnum.doSomething();
}
}
這些都是一些很簡單的了解和總結,希望這些能夠幫助到大家:
源碼下載下傳位址:源代碼下載下傳