大家好,又见面了,我是你们的朋友全栈君。
闲来无事看之前的博客,发现单例模式只会写2中。所以再重新开一篇博客,将目前自己所能理解的几种单例模式全部总结下。
___________________________________________________________________________________________________________
1、懒汉式(最基本的) 单线程版
写单例模式(饿汉式)的步骤:
1):必须在该类中,自己先创建出一个对象。
2):私有化自身的构造器,防止外界通过构造器创建新的对象。
3):想外暴露一个公共的静态方法用于获取自身的对象
缺点:单线程是没问题的 但是多线程就会产生线程问题 下面会介绍多线程版本
// 懒汉式类初始化的,不会创建该对象,真正需要的时候才会加载(创建),天生线程不安全,需要解决线程安全问题,所有效率比较低
public class SingletonLazy {
private SingletonLazy() {
System.out.println(Thread.currentThread().getName());
}
private static SingletonLazy singletonLazy;
public static SingletonLazy getInstance() {
if (singletonLazy == null) {
singletonLazy = new SingletonLazy();
}
return singletonLazy;
}
public static void main(String[] args) {
SingletonLazy singletonLazy1 = SingletonLazy.getInstance();
SingletonLazy singletonLazy2 = SingletonLazy.getInstance();
System.out.println(singletonLazy1 == singletonLazy2); // true
}
}
多线程版本线程不安全(最简单的案例):
public class SingletonLazy {
private SingletonLazy() {
System.out.println(Thread.currentThread().getName());
}
private static SingletonLazy singletonLazy;
public static SingletonLazy getInstance() {
if (singletonLazy == null) {
singletonLazy = new SingletonLazy();
}
return singletonLazy;
}
public static void main(String[] args) {
for (int i = 0; i <= 500; i++) {
new Thread(() -> {
try {
getInstance();
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
2、饿汉式(最基本的)
优点:线程天生安全 类在整个生命周期中只会被加载一次,因此该单例类只会创建一个实例,也就是说,线程每次都只能也必定只可以拿到这个唯一的对象
缺点:类加载的时候就会加载 static 对象 如果暂时用不到呢 就会占用极大的内存
public class SingletonHungry {
// 会浪费内存
// byte[] data1 = new byte[1024*1024];
// byte[] data2 = new byte[1024*1024];
private SingletonHungry() {
System.out.println(Thread.currentThread().getName());
}
//小知识: 当使用static 修饰时 会存档在 JVM的方法区 JVM垃圾回收机制 不会进行回收
private static final SingletonHungry singletonDemo = new SingletonHungry();
private static SingletonHungry getInstance() {
return singletonDemo;
}
public static void main(String[] args) {
SingletonHungry singletonDemo = getInstance();
SingletonHungry singletonDemo2 = getInstance();
System.out.println(singletonDemo == singletonDemo2); // true
}
}
3、枚举
枚举是一个特殊的类
内部将构造器进行私有化,因此不能通过New 的方式进行创建
有兴趣可以测试下 ,我这比较简单
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}
4、静态内部类
public class SingletonStatic {
private SingletonStatic() {}
public static class SingletonClassInstance{
private static final SingletonStatic single = new SingletonStatic();
}
public static SingletonStatic getInstance(){
return SingletonClassInstance.single;
}
public static void main(String[] args) {
SingletonStatic singleton1 = SingletonStatic.getInstance();
SingletonStatic singleton2 = SingletonStatic.getInstance();
System.out.println(singleton1 ==singleton2);
}
}
5、DCL(双重检验锁)
在 new MultiSingletonDCL();时候由于会发生指令重排序 可能会出现问题 因此加上关键字 volatile
// 1. 分配内存空间
// 2. 执行构造方法,初始化对象
// 3. 把这个对象指向这个空间
// 双锁机制的出现是为了解决前面同步问题和性能问题
public class SingletonDCL {
private volatile static MultiSingletonDCL multiSingletonDCL;
private SingletonDCL() {
System.out.println(Thread.currentThread().getName());
}
private static SingletonDCL getInstance() {
if (singletonLazyDCL == null){
synchronized (SingletonDCL.class){
if (singletonLazyDCL == null){
singletonLazyDCL = new SingletonDCL();
}
}
}
return singletonLazyDCL;
}
public static void main(String[] args) {
SingletonDCL instance = SingletonDCL.getInstance();
SingletonDCL instance2 = SingletonDCL.getInstance();
System.out.println(instance == instance2);
}
}
本文如有问题,希望大佬指正。不胜感激。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/147130.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...