1.饿汉式(线程安全)
1.创建私有的静态的final修饰的常量,静态的,在类加载机制的(加载,连接,初始化,使用,卸载)步骤中的连接中的(验证,准备,解析)中的准备阶段就会给静态变量分配内存空间,但这个时候是默认值,初始值是在初始化过程中,新建该类对象。
private static final 类 INSTANCE = new 类();
2.构造方法私有,如果我们不写,默认是无参,我们需该权限为private
private 类(){
}
3.提供获取对象方法,这样,外部就只能通过getInstance方法获取对象,并且这个对象是final修饰的。
public 类 getInstance(){
return INSTANCE;
}
这个时候有人提出来了,假如我不用这个对象,那在类加载的时候依然分配内存空间,岂不是空间浪费呢?其实我想说的是,你不用它,初始化它干啥?类只有在首次+主动使用(主动使用:反射,创建该类对象,调用该类静态方法或静态变量,初始化该类子类等等)才会触发初始化。不过为了解决这个问题,仍然有方案,请跟我来~~~~~~
2.懒汉式(线程不安全,在多线程下会new出多个对象,违背了单例原则,加锁)
public class 类{
/*volatile关键字,JMM 修饰变量是变量的值在主内存里改变,主内存会告诉cpu,cpu重新读值。就好像线程通信。
主内存的内容会被cpu执行的线程读取,但多个线程,有一个线程改变了主内存里的值,volatile关键字会起到通知
其他线程的缓冲区,(线程执行的时候会把主内存里的某个值读取到自己的缓冲区里,然后不停的读取缓冲区里的
值,如果是死循环,会一致重复下去,如果有睡眠或者其他闲置时间,这个线程可能会去主内存中在读取一次变量,
但这个不确定,有问题有隐患。)做到同步。线程之间的可见性,无锁同步。对公共的变量+volatile,
如果不加这个只能用synchronized,效率很低。*/
private volatile static 类 instance = null;
//私有构造
private 类(){}
//加锁后获取对象方式
public static 类 getInstance(){
if(instance==null){
synchronized(类.class){
//双重判断的重要性,在上层判断的时候,可能会有多个线程满足,线程并发,违背单例
if(instance==null){
instance=new 类();
}
}
}
return instance;
}
}
这样呢,是解决了初始化就创建对象的内存浪费问题,只有在我们调用getInstance方法的时候才会创建对象,但是加锁会使效率降低,那怎么办呢?? 跟我来~~~~~
3.静态内部类实现方法(类加载内部类不会被初始化,只有外部调用静态方法,静态方法里有静态内部类的对象初始化的时候,才会初始化内部类,同时创建了静态内部类中的创建外部类的对象)
public class 类{
private static class 单例{
//内部类可以访问外部类,外部类访问内部类需要创建内部类对象才可以。
private static final 类 INSTANCE = new 类();
}
//对外提供访问内部类获得对象的方法
public 类 getInstance(){
return 单例.INSTANCE;
}
}
4.枚举实现单例模式
public enum ObjInstance{
INSTANCE;
private Obj obj = null;
private ObjInstance(){
obj = new Obj();
}
public Obj getInstance(){
return obj;
}
}
来源:CSDN
作者:氵何章怀晓 。
链接:https://blog.csdn.net/GiantCrocodile/article/details/104307872