单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”
所有类都有构造方法,不编码则系统默认生成空的构造方法,若有显示定义的构造方法,默认的构造方法就会失效。
分析:
1、通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象;
一个最好的办法就是,让类自身负责保存它的唯一实例;这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
2、单例模式因为封装了它的唯一实例,这样它可以严格地控制客户怎样访问它以及何时访问它。简单地说就是对唯一实例的受控访问。
实用类与单例区别?
比如实用类不保存状态,仅提供一些静态方法或静态属性让你使用,而单例类是有状态的;
实用类不能用于继承多态,而单例虽然实例唯一,却是可以有子类来继承。
实用类只不过是一些方法属性的集合,而单例却是有着唯一的对象实例。
单例模式的几种实现方式:
懒汉式:
package cn.pers.sample.singleton;
/**
* 懒汉式.用的时候再加载。<br/>
* (线程安全与否,与实现方式有关。调用效率不高,但是能延时加载)
* @author WeiSong <br>
* @since 0.0.1
* 2020/11/12 15:29
*/
public class SingletonLazy {
private static SingletonLazy instance;
private SingletonLazy() {
}
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
//实现方式二 安全的实现方式
// public static synchronized SingletonLazy getInstance() {
// if (instance == null) {
// instance = new SingletonLazy();
// }
// return instance;
// }
}
饿汉式:
package cn.pers.sample.singleton;
/**
* 饿汉式。提前加载好,用的时候直接取 <br/>
* (线程安全,调用效率高,但是不能延时加载)
* @author WeiSong <br>
* @since 0.0.1
* 2020/11/12 15:31
*/
public class SingletonHungry {
private static SingletonHungry instance = new SingletonHungry();
private SingletonHungry() {
}
public static SingletonHungry getInstance() {
return instance;
}
}
双重检查:
package cn.pers.sample.singleton;
/**
* 基于懒汉式的双重检查.用的时候再加载,避免出现多线程同时创建。<br/>
* (相对线程安全,但某些场景下也会有问题)
* @author WeiSong <br>
* @since 0.0.1
* 2020/11/12 15:33
*/
public class SingletonDoubleCheck {
private static SingletonDoubleCheck instance;
private SingletonDoubleCheck() {
}
public static SingletonDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingletonDoubleCheck.class) {
if (instance == null) {
instance = new SingletonDoubleCheck();
}
}
}
return instance;
}
}
静态内部类:
package cn.pers.sample.singleton;
/**
* 静态内部类。<br/>
* (线程安全,调用效率高,可以延时加载)
* @author WeiSong <br>
* @since 0.0.1
* 2020/11/12 15:35
*/
public class SingletonInnerStatic {
private SingletonInnerStatic() {
}
public static SingletonInnerStatic getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
private static SingletonInnerStatic instance = new SingletonInnerStatic();
}
}
枚举式:
package cn.pers.sample.singleton;
/**
* 枚举式<br/>
* (线程安全,调用效率高,不能延时加载,自动支持序列化机制,绝对防止多次实例化,防止反射和反序列化调用)
* effective java中建议使用枚举. 枚举中创建的,在虚拟机中都是 final 和 static的,所以是安全的
*
* @author WeiSong <br>
* @since 0.0.1
* 2020/11/12 15:31
*/
public enum SingletonEnum {
/** 枚举对象 */
INSTANCE;
public void method() {
System.out.println("this is my define methods..");
}
/**
* 使用方式.
* @param args
*/
public static void main(String[] args) {
SingletonEnum.INSTANCE.method();
}
}
综上,建议使用 枚举和内部类。