图图在为毕业设计的事忙来忙去,有时间就回来讲故事。
图图在为面试做准备,今天图图给大家细说一番单例模式。其实最简单的是工厂模式而不是单例(工厂后续会说)
设计模式是一种思想,最早用于建筑,后来也用到我们软件开发上来,是牛人总结的一些常见的架构思想,按照六中原则设计出来的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");
}
}