首页 > 其他分享 >单例设计模式

单例设计模式

时间:2023-02-28 16:11:43浏览次数:40  
标签:SingleTon singleTon private static 单例 线程 设计模式 public

单例模式:
定义:某个类在某个系统中只能有一个实例化对象被获取和使用
实现要点: 1.构造器私有
2.含有一个该类的静态变量保存这个唯一实例
3.对外提供获取该实例对象的方式
分类:1.饿汉式 2.懒汉式
下面对这两种单例模式展开分析,进行对比

饿汉式
1.代码实现1(静态常量方式实现)

public class SingleTon{
private static final SingleTon singleTon = new SingleTon();
private SingleTon(){}
public static SingleTon getSingleTon(){
return singleTon;
}
}

2.代码实现2(静态代码块方式实现)

`public class SingleTon{
private staic SingleTon;
//在代码块执行时,创建单例对象
static{singleTon = new SingleTon();}

private SingleTon(){}
public static SingleTon getSingleTon(){
return singleTon;}
}`

public class TestSingleTon{ public static void main(Stirng[] args){ SingleTon s1 = SindleTon.getSingleTon; SingleTon s2 = SindleTon.getSingleTon; System.out.println(s1 == s2); //true } }

3.特点及代码分析
1)私有化构造器
2)在类的内部创建一个类的实例,static
3)私有化对象,通过公共方法调用
4)此方法只能通过类来调用,因为是static的,类的实例也是static的
5)只创建一个对象,不会有线程不安全的情况
6)在类加载是就完成了类实例化,避免了线程同步问题,但没有达到Lazy Loading的效果,如果没有使用过这个对象,会造成内存浪费
7)如何避免这种情况发生呢?可以采用枚举形式实现单例模式
代码块如下:
public enum SingleTon{ INSTANCE; }

懒汉式
1.代码实现1(线程不安全方式)

public class SingleTon{ private SingleTon(){} private static SingleTon singleTon = null; //当调用方法时,才创建单例对象 public static SingleTon getSingleTon(){ if(singleTon == null){ singleTon = new SingleTon(); } return singleTon; } }

2.代码分析1
1)起到了lazy Loading的作用,即延迟加载对象,但只能在单线程时使用
2)如果早多个线程下,一个线程进入了if(singleTon == null)判断语句时,若满足条件判断且还没来得及继续执行,另一个线程也进入到if(singleTon == null)判断语句,这就会产生多个实例对象,即线程不安全。
3.代码实现2(线程安全方式\双重检查)

public class SingleTon{ private SingleTon(){} private static SingleTon singleTon = null; //当调用方法时,才创建单例对象 public static SingleTon getSingleTon(){ if(singleTon == null){//第一层检查,检查是否有引用对象,如果一个线程获取了实例,则不需要进入同步代码块中了 synchronized (SingleTon.class){//第一层锁,保证只有一个线程进入。同步代码块使用的锁是单例的字节码文件对象,且只能用这个锁 if(singleTon == null){ //第二层检查 singleTon = new SingleTon(); } } return singleTon; } }

4.代码分析2
//volatile关键字的作用为禁止指令重排,保证返回singleTon对象一定在创建对象后
singleTon = new SingleTon();该语句的底层实现逻辑为:
(1)在堆上开辟空间
(2)属性初始化
(3)引用指向对象
//假设以上三个内容为三条单独指令,因指令重排可能会导致执行顺序为1->3->2(正常为1->2->3),当单例模式中存在普通变量需要在构造方法中进行初始化操作时,单线程情况下,顺序重排没有影响;但在多线程情况下,假如线程1执行singleton=new Singleton()语句时先1再3,由于系统调度线程2的原因没来得及执行步骤2,但此时已有引用指向对象也就是singleton!=null,故线程2在第一次检查时不满足条件直接返回singleton,此时singleton为null(即str值为null)
//volatile关键字可保证singleton=new Singleton()语句执行顺序为123,因其为非原子性依旧可能存在系统调度问题(即执行步骤时被打断),但能确保的是只要singleton!=0,就表明一定执行了属性初始化操作;而若在步骤3之前被打断,其他线程可进入第一层检查向下执行创建对象.此时线程2拿到的不是一个null singleton,而是一个没有被步骤2正确初始化的singleton。

5.代码实现3(静态内部类)
//懒汉式:静态内部类形式
public class SingleTon { private SingleTon(){ } private static class Inner{ private static final SingleTon SINGLE_TON = new SingleTon(); } public static SingleTon getSingleTon(){ return Inner.SINGLE_TON; } }
//分析:(1)只有在调用方法时,才会加载到内部类,从而完成类的实例化,singleTon。
(2)避免了线程不安全,利用静态内部类特点实现延迟加载,效率高。

6.实际应用
`public class LazySingleDesign {
private static LazySingleDesign lazySingleDesign = null ;
private LazySingleDesign(){}

public static LazySingleDesign getInstance(){
synchronized(LazySingleDesign.class){
if(lazySingleDesign == null){
lazySingleDesign = new LazySingleDesign();
}
}
return lazySingleDesign;
}
}`

@Test public void test() { ExecutorService executor = Executors.newFixedThreadPool(10); for(int i = 0 ; i < 10;i++){ executor.execute(new Runnable() { @Override public void run() { LazySingleDesign user = LazySingleDesign.getInstance(); System.out.println("design = " + user); } }); } }

getInstance()方法内的第一个if判断可以去掉,生成的也是单例。另外可见性可以去掉也不影响生成的单例。

参考文章链接:1.https://blog.csdn.net/weixin_42617262/article/details/90448083
2.https://big-data.blog.csdn.net/article/details/83422780?spm=1001.2101.3001.6650.9&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-9-83422780-blog-115265060.pc_relevant_3mothn_strategy_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-9-83422780-blog-115265060.pc_relevant_3mothn_strategy_recovery&utm_relevant_index=16
3.https://blog.csdn.net/qq_42804736/article/details/115265060

标签:SingleTon,singleTon,private,static,单例,线程,设计模式,public
From: https://www.cnblogs.com/zWANG97/p/17163330.html

相关文章

  • 设计模式(十二)----结构型模式之代理模式和装饰者模式的区别
    1、代理和装饰者的区别静态代理和装饰者模式的区别:相同点:都要实现与目标类相同的业务接口在两个类中都要声明目标对象都可以在不修改目标类的前提下增强目标......
  • 设计模式(十三)----结构型模式之桥接模式
    1概述现在有一个需求,需要创建不同的图形,并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系:我们可以发现有很多的类,假如我们再增加一个形状或......
  • 设计模式:创建型
    简单工厂模式1publicinterfaceComputer{23voidsetComputerSystem();45}67publicclassXiaoMiComputerimplementsComputer{89......
  • 模板设计模式
    1、什么是模板设计模式把抽象类(AbstractClass)整体看作是一个模板,模板中不能决定的东西定义成抽象方法(AbstractMethod),让继承的子类去重写抽象方法实现需求。2、使用......
  • C# 单例
    [STAThread] privatestaticvoidMain() { if(Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length>1) { Environment.Exit(1......
  • 代理设计模式还不会?2分钟搞定
    概述代理模式就是给某一个对象提供一个代理,并由代理对象控制对原对象的引用。在一些情况下,一个客户不想或者不能直接引用一个对象,而代理对象可以在客户端和目标对象之间起......
  • WinUI的单例实现方法
    在OnLaunched中处理单例打开App.xaml.cs文件,编辑OnLaunched方法protectedoverrideasyncvoidOnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgsargs){ va......
  • 03_16_JavaWeb||day19_Filter&Listener||day19_Filter&代理模式(23种设计模式之一:用来
    今日内容*Servlet,Filter,Listener被称为JavaWeb三大组件1.Filter:过滤器2.Listener:监听器1.Filter:过滤器概念:生活中的过滤器:净水器,空气净化器,土匪、web中的过滤器:当......
  • 简单熟悉下设计模式
    寻找到底用的什么设计模式目录寻找到底用的什么设计模式11.背景11.1.海超写的es,在枚举里面完成了各个方法的调用.感觉很厉害看下12.先熟悉下23中设计模式1......
  • 设计模式之装饰器模式
    设计模式之装饰器模式1.解释装饰器模式(DecoratorPattern)也称为包装模式(WrapperPattern)是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的......