单例模式
确保一个类只有一个实例,而且自行实例化,向整个系统提供这个实例
不提供构造方法,将构造方法私有化
饿汉式
通过将本类作为当前类的静态常量,通过一个静态方法访问
优点:写法简单,类加载时就完成实例化,避免了线程同步问题
缺点:可能有其他途径产生类加载,且未使用到该实例化对象造成资源浪费
在静态常量中直接实例化对象
public class Hungry {
//直接实例化一个本类对象作为本类的类变量
public static final Hungry HUNGRY = new Hungry();
//构造方法私有化,其他类无法访问进行本类的实例化
private Hungry() {
}
//实例化一个本类对象作为本类的类变量
public static final Hungry HUNGRY = new Hungry();
//提供一个静态方法用于获取本类的实例化对象
public static Hungry getInstance() {
return HUNGRY;
}
}
在静态代码块中实例化对象
public class Hungry {
//构造方法私有化,其他类无法访问进行本类的实例化
private Hungry() {
}
private static Hungry HUNGRY;
//在静态代码块中实例化对象
static {
HUNGRY = new Hungry();
}
//提供一个静态方法用于获取本类的实例化对象
public static Hungry getInstance() {
return HUNGRY;
}
}
懒汉式
提供一个公有的静态方法,调用静态方法时再进行对象实例化
线程不安全写法
不要在开发中使用,只能在单线程中使用,存在线程安全问题
public class Lazy {
private Lazy() {
}
public static Lazy lazy;
//判断是否需要进行对象实例化
public static Lazy getInstance() {
if (lazy == null) {
lazy = new Lazy();
}
return lazy;
}
}
线程安全,同步写法
方法进行同步效率太低,实际开发不推荐使用
public class Lazy {
private Lazy() {
}
public static Lazy lazy;
//提供一个公有的静态方法,加入同步处理的代码,解决线程安全问题
public static synchronized Lazy getInstance() {
if (lazy == null) {
lazy = new Lazy();
}
return lazy;
}
}
在方法中改成同步产生实例化的代码块,同样不能使用,存在线程安全问题
双重检查
多线程开发常使用,进行两次实例化对象的检查,第一个线程进入后实例化代码执行了一次,后面线程再进来,实例化代码不再执行,直接返回实例化对象,也避免了反复进行方法同步
优点:线程加载;延迟加载;效率较高;实际开发推荐使用
public class DoubleCheck {
private DoubleCheck() {
}
//volatile防止指令重排
private static volatile DoubleCheck doubleCheck;
public static DoubleCheck getInstance() {
//第一重检查
if (doubleCheck == null) {
synchronized (DoubleCheck.class) {
//第二重检查
if (doubleCheck == null) {
doubleCheck = new DoubleCheck();
}
}
}
return doubleCheck;
}
}
静态内部类实现单例
public class Singleton {
private Singleton() {
}
//在静态内部类声明一个本类的静态常量,进行实例化
public static class SingletonInstance {
private static final Singleton SINGLETON = new Singleton();
}
//通过调用静态内部类的静态属性返回实例化对象
public static Singleton getInstance() {
return SingletonInstance.SINGLETON;
}
}
枚举方式
可以避免多线程问题,而且还能防止反序列化重新创建新的对象
public class EnumSingleton {
private EnumSingleton() {
}
enum Singleton {
ENUM_SINGLETON;
public void sayOk() {
System.out.println("ok=-=");
}
}
}
public class GetEnumSingleton {
public static void main(String[] args) {
EnumSingleton.Singleton enumSingleton = EnumSingleton.Singleton.ENUM_SINGLETON;
EnumSingleton.Singleton enumSingleton1 = EnumSingleton.Singleton.ENUM_SINGLETON;
System.out.println(enumSingleton1 == enumSingleton);
enumSingleton.sayOk();
}
}