文章目录
1.描述
单例模式、Singleton。是一种创建型设计模式,能保证一个类只有一个实例(对象),并全局可以访问该实例。
主要解决:一个全局使用的类频繁创建销毁带来的不必要的开销。
举个栗子:工具类
源码在文末
2.介绍六种写法
2.1.双重校验锁/双检锁(DCL,double-checked locking)
使用了双锁机制,在多线程并发情况下也能保证高性能。synchronized
给类加锁,整个类只有一个线程可以拿到锁,这块知识可以自行学习一下synchronized
;volatile
可见性,防止CPU指令重排,防止对象半初始化的时候出现问题。
如果类里面还有成员变量,在为加volatile
的时候,JVM指令重排,成员变量初始化的时候有空指针的风险。
面试比较容易问这种。
线程安全。懒加载(lazy loading)。
/**
* 双重锁校验/双检锁(DCL,double-checked locking)
* <p>
* 多线程并发情况下也能保持高性能和单例
*
* @author 编程还未
*/
public class Singleton {
/**
* 注意这里的 volatile ,面试经常问到
*/
private volatile static Singleton singleton;
private Connection connection;
private Singleton() {
//connection初始化
// this.connection=
}
/**
* 获取单例对象的方法
*
* @return 单例对象
*/
public static Singleton getSingleton() {
if (singleton == null) {
//注意这里的 synchronized
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
2.2.Holder方式/静态内部类
能达到DCL(双检锁)一样的效果,但是比DCL简单。
借助了类加载特点,classloader机制保证初始化的时候只有一个线程。
JVM会加载Singleton类,内部类Holder在调用getSingleton()方法的时候才会被加载。
推荐这种写法,比较简单。
线程安全。懒加载。
/**
* 静态内部类
* <p>
* 线程安全
*
* @author 编程还未
*/
public class Singleton {
/**
* 静态内部类
*/
private static class Holder {
private static final Singleton SINGLETON = new Singleton();
}
private Singleton() {
}
/**
* 获取对象的方法
*
* @return 单例对象
*/
public static Singleton getSingleton() {
return Holder.SINGLETON;
}
}
2.3.饿汉式
实例作为类变量并直接初始化。类加载的时候就会被加载,以及只要出发类加载机制就会被创建一次对象,容易产生垃圾对象。
能保证线程安全,没有懒加载会浪费内存。这个名字比较抽象,为什么叫饿汉式?因为在类加载的时候就实例化对象了,像个饿汉子很着急。
这种属于知道就可以,没有用于生产的价值。
线程安全。非懒加载。
/**
* 饿汉式
*
* @author 编程还未
*/
public class Singleton {
private static Singleton SINGLETON = new Singleton();
private Singleton() {
}
/**
* 获取对象
*
* @return 单例对象
*/
public static Singleton getInstance() {
return SINGLETON;
}
}
3.4.懒汉式(线程不安全)
最基本的实现方式,但是非线程安全。这个名字比较抽象,为什么叫懒汉式?因为在使用的时候才会实例化对象,不像饿汉子那般着急。
这种属于知道就可以,没有用于生产的价值。
非线程安全。懒加载。
/**
* 懒汉式
* <p>
* 非线程安全
*
* @author 编程还未
*/
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3.5.懒汉式(线程安全)
上面的改良版。加锁,所以在多线程下可以工作。但是正因为,只能有一个线程访问,效率比较低。
这种属于知道就可以,没有用于生产的价值。
线程安全。懒加载。
/**
* 懒汉式
* <p>
* 线程安全
*
* @author 编程还未
*/
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2.6.枚举方式
Java经典图书《Effective Java》作者力推,很多优秀开源代码中使过枚举的方式实现单例。枚举不可以被继承、提供串行化机制,线程安全只能被实例化一次,也能应对反射攻击。但是不能懒加载。
也许,这才是单例的最佳写法。
线程安全。非懒加载。
/**
* 枚举方式
*
* @author 编程还未
*/
public enum Singleton {
SINGLETON;
/**
* 类方法
* <p>
* 使用的时候直接 Singleton.SINGLETON.getStr();
*/
public String getStr() {
return "编程还未";
}
}