1、什么是单例模式?
Java单例模式是一种设计模式,用于确保一个类只有一个实例,并提供全局访问点以获取该实例。它通常用于需要共享资源或控制某些共享状态的情况下。
2、实现方式
懒汉式:在类加载的时候就创建对象,要再调用方法时才创建对象,减少内存开销。
饿汉式:再类加载的时候就实例化对象。
2.1 同步方法调用创建实例(懒汉式)
当刚加载这个类时不会直接初始化person,只有调用getPerson()方法时才会构建唯一实例。
public class Person {
private static Person person;
//将构造器私有化,就无法从外部调用构造器构造对象
private Person(){}
//此时这个synchronized是保证线程安全
public synchronized static Person getPerson() {
if (person == null) {
person = new Person();
}
return person;
}
}
2.1 双重校验锁方式加载对象实例(懒汉式)
用两个判断,在第一个判断不通过时,我们不用同步代码块,直接返回结果
public class Person {
//此时要用volatile用于保证person = new Person()内部指令不排序
private volatile static Person person;
//将构造器私有化,就无法从外部调用构造器构造对象
private Person(){}
public static Person getPerson() {
if (person ==null){
synchronized (Person.class){
if (person == null){
person = new Person();
}
}
}
return person;
}
}
2.1 静态变量加载对象实例(饿汉式)
对象唯一实例会随着这个类的加载就会被初始化出来,基于 classloader 机制避免了多线程的同步问题,但它再还没有使用这个对象时就被加载出来,有点浪费内存空间。
public class Person {
private static Person person = new Person();
//将构造器私有化,就无法从外部调用构造器构造对象
private Person(){}
public static Person getPerson() {
return person;
}
}
2.1 静态内部类实现单例模式(懒汉式)
这里用到了一个知识点,就是内部类不会随着外部类的加载而加载,而是再第一次使用到内部类后再加载初始化内部类。这样的机制实现了懒汉模式。我们使用了final修饰,也将其确定为单例模式。
public class Person {
private static class PersonHolder {
private static final Person INSTANCE = new Person();
}
//将构造器私有化,就无法从外部调用构造器构造对象
private Person (){}
public static final Person getInstance() {
return PersonHolder.INSTANCE;
}
}
2.1 枚举实现单例模式(饿汉式)
这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
完整的枚举单例
public class User {
//私有化构造函数
private User(){ }
//定义一个静态枚举类
static enum SingletonEnum{
//创建一个枚举对象,该对象天生为单例
INSTANCE;
private User user;
//私有化枚举的构造函数
private SingletonEnum(){
user=new User();
}
public User getInstnce(){
return user;
}
}
//对外暴露一个获取User对象的静态方法
public static User getInstance(){
return SingletonEnum.INSTANCE.getInstnce();
}
}
public class Test {
public static void main(String [] args){
System.out.println(User.getInstance());
System.out.println(User.getInstance());
System.out.println(User.getInstance()==User.getInstance());
}
}
结果为true