小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
单例模式
特点
- 只有一个实例
- 提供了一种访问其唯一的对象的方式
- 构造函数是私有的
- 自己创建唯一实例
使用场景
- 其对象是唯一的,比如唯一的男/女朋友,唯一的主席,唯一的班主任
- 在多线程中为了防止多个线程访问同一个资源文件,所以访问文件的对象是单例的
实现逻辑
- 构造方法都是私有的
- 有一个方法供获取对象getInstance()
- new对象之前需要判断对象是否存在,存在则直接返回存在的对象,不存在才进行new
实现代码
public class SingleObject{
private SignleObject singleton;
private SignleObject(){
//1. 构造方法私有
}
//2. 一个方法获取对象
public static SignleObject getInstance(){
//3. 不存在才new
if(singleton==null){
singleton=new SignleObject();
return singleton;
}else{
return singleton;
}
}
public void sayMe(){
System.out.print("singleObject")
}
}
方法调用
public class SingletonPatternDemo {
public static void main(String[] args) {
//不合法的构造函数
//编译时错误:构造函数 SingleObject() 是不可见的
//SingleObject object = new SingleObject();
//获取唯一可用的对象
SingleObject object = SingleObject.getInstance();
//显示消息
object.showMessage();
}
}
几种实现方式及特点
懒汉式 线程不安全
懒汉式:私有静态变量只有在第一次用的时候才会加载,不用就不会加载
线程不安全:多个线程同时通过了if (singleton == null)
的判断逻辑,从而导致生成了多个对象
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
懒汉式 线程安全
即针对getInstance
方法加锁,即同一时间进入该方法的只有一个线程
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
饿汉式
直接加载一个对象,这样就不会出现线程不安全的情况了
private static Singleton instance = new Singleton();
双检锁/双重校验锁(DCL:double checked locking)
相对于懒汉式线程安全增加了
- 先判断object不存在再加锁
- 锁内再判断一次
相对于懒汉式线程安全的情况,先进行object==null
的判断再加锁.可以提升并发行,因为懒汉式先加锁再判断如果!=null
的时候也会进行加锁
而双层判断,防止都通过第一层判断加锁了之后就一定会生成两个对象
public static Signleton getInstance(){
if(signleton == null){
synchronized (Signleton.class){
if(signleton == null){
signleton == new Signleton();
}
}
}
}
登记式/静态内部类(未理解)
Loading...
只有当调用 getInstance()
方法从而触发 SingletonHolder.INSTANCE
时 SingletonHolder
才会被加载
,JVM 能确保 INSTANCE 只被实例化一次.
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举实现(未理解)
Loading... 通过反射机制,是可以实例化构造方法为private类的. 枚举实现自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
只能说更安全