圖圖在為畢業設計的事忙來忙去,有時間就回來講故事。
圖圖在為面試做準備,今天圖圖給大家細說一番單例模式。其實最簡單的是工廠模式而不是單例(工廠後續會說)
設計模式是一種思想,最早用于建築,後來也用到我們軟體開發上來,是牛人總結的一些常見的架構思想,按照六中原則設計出來的23中設計模式
單例模式:是23中設計模式稍簡單的設計模式,也是很常見的設計模式, java中一般展現在架構的整體架構,面向接口程式設計,用這種思想完成某個領域的解決方案。
當然實作單例功能後,保證線程安全,并發效率快,消耗資源率少的原則才是最perfect。
詳情請往下看。
單例模式自身的初衷在于應用程式一啟動,單例資源一次性永久駐留記憶體的思想,
package org.huey.pattern.singleton1;
/**
* 懶漢式單例模式
* @author huey
*
*/
public class HungryStyle {
//public Integer number;
//private Integer number;
/**
* 類屬性,天然線程安全
*/
private static HungryStyle hungryStyle = new HungryStyle();
private HungryStyle() {
}
public static HungryStyle getInstance() {
return hungryStyle;
}
}
複制
餓漢式
缺點:上來就建立對象,立刻加載,如果我不用getInstance方法的話,那麼就浪費了建立所耗的資源。
優點:類屬性線程安全,方法不用同步鎖也沒有并發問題,調用效率高。
package org.huey.pattern.singleton1;
/**
* 懶漢式加載
* @author huey
*
*/
public class LazyStyle {
private static LazyStyle lazyStyle;
private LazyStyle() {
}
public synchronized static LazyStyle getInstance() {
if (lazyStyle == null) {
//---------------此處如果有多個線程通路,一個線程挂機,當另一個線程進來時,lazyStyle依然為null
//那麼就都去new對象了,失去了初衷(隻建立一次),故加上synchronized同步鎖
lazyStyle = new LazyStyle();
}
return lazyStyle;
}
}
複制
懶漢式
缺點:由于存在并發問題,需要加上同步鎖解決線程安全問題,故調用效率低。
優點:使用的時候再建立,資源使用率高。
package org.huey.pattern.singleton1;
/**
* 靜态内部類的單例模式
* @author huey
*
*/
public class StaticInnerStyle {
//靜态内部類不會随這類加載而加載,當你調用getInstance方法才會加載該内部類,也就是懶加載
private static class SingletionClass{
//類屬性,線程安全
private static final StaticInnerStyle instance = new StaticInnerStyle();
}
//不用同步鎖,調用效率高
public static StaticInnerStyle getInstance(){
return SingletionClass.instance;
}
private StaticInnerStyle(){}
}
複制
靜态内部類的單例:
優點:高效(不用同步鎖) 線程安全(靜态類屬性) 懶加載(使用時我才建立)
package org.huey.pattern.singleton1;
/**
* 枚舉類型的單例模式
* @author huey
*
*/
public enum EnumStyle {
//枚舉天然是單例,jvm的底層實作,不過用枚舉實作單例,要求隻有這一個對象
INSTANCE;
//INSTANCE,SPRING;這樣如果測試INSTANCE與SPRING不是通一個對象
public void service(){
System.out.println("業務操作....");
}
}
借助jad工具進行反編譯,代碼如下
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: EnumStyle.java
//反編譯
package org.huey.pattern.singleton1;
import java.io.PrintStream;
public final class EnumStyle extends Enum
{
private EnumStyle(String s, int i)
{
super(s, i);
}
public void service()
{
System.out.println("\u4E1A\u52A1\u64CD\u4F5C....");
}
public static EnumStyle[] values()
{
EnumStyle aenumstyle[];
int i;
EnumStyle aenumstyle1[];
System.arraycopy(aenumstyle = ENUM$VALUES, 0, aenumstyle1 = new EnumStyle[i = aenumstyle.length], 0, i);
return aenumstyle1;
}
public static EnumStyle valueOf(String s)
{
return (EnumStyle)Enum.valueOf(org/huey/pattern/singleton1/EnumStyle, s);
}
public static final EnumStyle INSTANCE;
private static final EnumStyle ENUM$VALUES[];
static
{
INSTANCE = new EnumStyle("INSTANCE", 0);
ENUM$VALUES = (new EnumStyle[] {
INSTANCE,
});
}
}
複制
反編譯後,會學到很多知識,數組的最佳複制操作,字元串轉為Unicode的碼,還有一個是目标匿名内部類的數組形式,頭一次發現,學到了不少東西,很開心。
其枚舉類型的單例 優點 線程安全,高效, 缺點是 沒有延遲加載(可通過反編譯代碼看出),還有就是隻有這種方式,可以避免反射(不考慮特殊處理)和反序列化漏洞,其他的形式的單例模式做不到這一點,換句話說反射和反編譯能破解其他形式的單例模式
注:
一般單例用途就是用在他的功能,隻加載一次就夠。比如springmvc的前端控制器,spring的ioc,加載配置檔案的配置器類,建立架構内部對象的工廠類,處理日志類等。
還有一種好像叫雙重内部鎖,由于該方式雙同步可能次序不易可能存在問題,就不說了,主要是沒研究過。。。。
附加Enum抽象類jdk源碼
/*
* @param <E> The enum type subclass
* @author Josh Bloch
* @author Neal Gafter
* @see Class#getEnumConstants()
* @see java.util.EnumSet
* @see java.util.EnumMap
* @since 1.5
*/
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
private final String name;
public final String name() {
return name;
}
private final int ordinal;
public final int ordinal() {
return ordinal;
}
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public String toString() {
return name;
}
public final boolean equals(Object other) {
return this==other;
}
public final int hashCode() {
return super.hashCode();
}
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
public final int compareTo(E o) {
Enum other = (Enum)o;
Enum self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
public final Class<E> getDeclaringClass() {
Class clazz = getClass();
Class zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? clazz : zuper;
}
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
throw new InvalidObjectException("can't deserialize enum");
}
private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("can't deserialize enum");
}
}
複制