单例模式
1.是什么
单例模式,本质上就是借助变成语言自身的语法特性,强行限制某个类,不能创建多个实例
由static引入单例模式
static关键字修饰的成员/属性 变成了类成员/类属性
其实当属性变成类属性的时候,此时就已经是“单个实例”
jvm针对某个.class文件只会加载一次,也就只有一个类对象,类对象上面的成员(static修饰)也就只有一份了
c语言中的static
1.修饰局部变量:改变了变量的声明周期
2.修饰全局变量,改变了变量的作用域
3.修饰函数,改变了函数的作用域
2.单例模式创建
饿汉模式
class Singleton{
private static Singleton instance=new Singleton();
public static Singleton getInstance(){
return instance;
}
//把 构造方法 设为private 此时在类的外面,就无法继续new 实例了
private Singleton(){
}
}
public class demo20{
public static void main(String[] args) {
//如果代码这么些,就违背初衷,就应该禁止在这个类的外部被new
// Singleton instance2=new Singleton();
Singleton instance=Singleton.getInstance();
}
}
上述代码里写的实现单例模式的方式,叫做饿汉模式
类加载阶段创建的实例,创建实例的时机非常早,非常急迫
懒汉模式
首次调用getinstance的时候才会触发,后续在调用getinstance就立即返回对象 因此,懒汉模式创建实例晚,但是效率更高
为什么懒汉模式的效率更高:
如果整个代码后续没人调用getInstance,这样就把构造实例的过程给省下来了
或者即使有代码后续调用getInstance,但是调用的时机,比较晚,这个时候,创建实例的时机也就延迟了,就和其他耗时操作岔开了(一般程序刚启动时,要初始化的东西很多,系统资源紧张
饿汉模式,懒汉模式谁更安全
考虑到这俩代码是否线程安全,本质上是在考虑,多个线程同时调用instance,是否会有问题
加锁修改懒汉模式使其安全
这样写虽然解决了线程安全问题,但是导致后续线程已经安全的时候,仍然还得加锁
线程不安全,只是实例创建之前(首轮调用时候)才会触发
修改代码:
实例没有创建之前,加锁,
实例创建之后,不加
中间隔着一个加锁操作,这就意味着这俩个if执行的时间间隔可能是沧海桑田(加锁可能会产生竞争,竞争就会导致阻塞,阻塞的话,啥时候唤醒,不一定了,有可能在这过程中另一个线程竞争到锁已经创建出了实例)
上述代码还会触发指令重排序问题:
new 操作的本质上也是三个步骤:
1.申请内存,得到内存首地址
2.调用构造方法,来初始化实例
3.把内存的首地址赋值给instance对象引用
如果先执行1,3在2执行之前,就得到了不完全的对象,
t2线程里面getInstance会认为instance非空,就直接返回Instance,并且在后续可能会针对instance进行解引用操作(使用里面的属性/方法)
只是有内存,但是内存上的数据是无效的
再次修改:
优化方案:volatile关键字(内存可见性,指令重排序):
> package Threading; //线程安全的懒汉模式 class SingletonLazy{
> private volatile static SingletonLazy instance=null;
> public static SingletonLazy getInstance(){
> if(instance==null){
> synchronized (Singleton.class){
> if(instance==null){
> instance=new SingletonLazy();
> }
> }
> }
> return instance;
> }
> private SingletonLazy(){}; } public class demo21 {
> public static void main(String[] args) {
> SingletonLazy instance=SingletonLazy.getInstance();
> } }
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。