 
                    
                
         
    
    
    
	
	
		
    
    
        
            
            
            
                
1.单例设计模式
确保某个类的对象在内存中只占有一份,节省资源空间
![]()
2.实现单例设计模式
分为两种设计,一种是饿汉式,简单粗暴;一种是懒汉式,面试会问
![]()
[1]饿汉式
先将类的构造方法私有化,让用户无法直接new对象,保证对象唯一
![]()
接着,我们在类里new一个对象,供用户使用
![]()
但是s是非静态成员,只能new对象才能获取,可构造方法已经被我们私有化,因此,我们加上static修饰,让用户通过类名直接获取
![]()
接着,我们调用两次s,很明显,两次调用的对象是同一个
![]()
还需要优化代码,使用public修饰,放大权限;使用final修饰,防止唯一的对象被用户恶意篡改
![]()
最简单的饿汉式写法就已经写好了
![]()
但是,这样写没有体现出面向对象思想,面向对象是通过调用方法去解决问题,所以,我们再写一个方法返回s,让用户掉用方法去获取对象更为合适
既然写了方法去获取对象,那么我们就需要私有化s,防止用户再类名调用s,既然私有化了s,也就不再需要final修饰了 如图
![]()
[2]懒汉式
懒汉式第一步也是先私有化构造方法
![]()
所谓懒汉式,就是很懒,先声明变量s,不进行初始化
![]()
当用户在调用方法获取对象时,此时再new对象,将对象返回给用户
![]()
但是这种写法,不能保证对象唯一
![]()
因为new了两次对象,调用一次getInstance就new了一个对象,调用两次自然两个对象
![]()
所以,我们要在方法里加入判断,当s为null时再new对象,如果s被创建了就不为null,也就不会再创建对象
![]()
上图只是懒汉式的入门写法,而且存在弊端,在多线程并发操作时,可能会创建出多个对象
![]()
原因分析
假设线程1拿到执行权,s此时为null,符合条件,线程1进入if内部
![]()
线程1刚要创建对象时,线程2抢到执行权,s还是null,线程2也进入if内部
两条线程都进入了if内部,后续不会再进行if判断,直接new了两个对象
![]()
所以,我们要使用线程同步,当线程在new对象时,其他线程不要打扰,这样就可以避免创建多个对象
![]()
右键运行,都是同一份地址
![]()
代码还需要优化,这样写还是存在弊端,效率太低了
如图,当线程1抢到执行权,上锁,此时线程2进入了阻塞状态
![]()
执行完毕后,线程2抢到执行权,上锁,线程1进入阻塞状态(括号里的阻塞代表阻塞的次数)
![]()
假设线程1再次抢到执行权,上锁,线程2就又进入阻塞状态,此时线程2已经阻塞了两次了
![]()
执行完毕,线程2抢到执行权,上锁,线程1也阻塞了两次
![]()
所以,代码这样写,每次执行任务时,就必然会有一方线程阻塞,效率非常低
但是,我们又无法避免阻塞的情况。既然无法避免,我们就要思考如何减少阻塞情况的发生
如图,我们在上锁前加上一个判断
![]()
假设线程1抢到执行权,s初始为null,进入if内部,此时,线程2抢到执行权,也进入if内部
![]()
线程1继续抢夺执行权,上锁,线程2第一次阻塞,满足if条件,创建对象
![]()
线程1执行完毕后,回到最外面,此时s已经创建好了,即便线程1抢到执行权也不满足第一个if的条件,不会再继续进入内部上锁
![]()
此时,线程2还在if内部,上锁,发现s不为null,释放锁,返回对象,执行结束
![]()
这时线程1、2都在最外面,发现s不为null,不满足第一个if条件,那就都不会进入if内部上锁,都直接返回对象了
![]()
这就是完整的懒汉式写法,也叫延迟加载模式
![]()
 
             
            posted @ 
2025-05-18 16:53 
直実 
阅读(
10) 
评论() 
 
收藏 
举报