单例模式:
核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
饿汉式:
/**
* 单利模式:饿汉式加载
* 饿汉单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。
* 因此,可以省略synchronized关键字
* 问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费。
* @author zw
*
*/
public class HungryLoad {
//类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然是线程安全的。
private static HungryLoad instance = new HungryLoad();
//私有化构造器。
private HungryLoad() {
}
//方法没有同步,调用效率高。
public static HungryLoad getInstance(){
return instance;
}
}
懒汉式
/**
* 单例模式:懒汉式加载
* 延迟加载,懒加载!真正用的时候才加载。
* 问题:资源利用率高了。但是每次调用getInstance()方法都要同步,并发效率较低。
* @author zw
*
*/
public class LazyLoad {
//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)
private static LazyLoad instance;
//私有化构造器
private LazyLoad() {
//防止通过反射创建多个对象
if (instance != null) {
throw new RuntimeException();
}
}
//方法同步,调用效率低。
public static synchronized LazyLoad getInstance(){
if (instance == null) {
instance = new LazyLoad();
}
return instance;
}
}
静态内部类
/**
* 单例模式:静态内部类(也是一种懒加载)
* 外部类没有static属性,则不会像饿汉式那样立即加载对象。
* 只有真正调用getInstance(),才会加载静态内部类,加载类时是线程安全的。instance是static final 类型,保证了内存中只有这样一个实例存在,
* 而且只能被赋值一次,从而保证了线程安全性。
* 兼备了并发高效调用和延迟加载的优势!
* @author zw
*
*/
public class StaticInnerclassLoad {
private static class InnerClass{
private static final StaticInnerclassLoad instance = new StaticInnerclassLoad();
}
private StaticInnerclassLoad() {
}
public static StaticInnerclassLoad getInstance() {
return InnerClass.instance;
}
}
枚举
/**
* 单例模式:枚举加载
* 实现简单
* 枚举本身就是单例模式,由JVM从根本上提供保障!避免通过反射和反序列化的漏洞!
* 问题:无延迟加载。
* @author zw
*
*/
public enum EnumLoad {
/**
* 定义一个枚举元素,它就代表了Singleton的一个实例
*/
INSTANCE;
/**
* 单例可以有自己的操作
* @return
*/
public void singletonOperation(){
//功能处理
System.out.println("枚举加载的功能");
}
}
开发时,如果类创建对象的代价很高,就用延时加载(懒汉式);类调用效率非常频繁,用饿汉式
单例对象:占用 资源少;不需要延时加载。
枚举式 好于 饿汉式
单例对象:占用 资源大;需要延时加载。
静态内部类式 好于 懒汉式
防止通过反射创建多个对象,在构造方法中加
if (instance != null) {
throw new RuntimeException();
}
单例模式应用的场景一般发现在以下条件下:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。