做视频网站软件长春网站制作设计
web/
2025/9/28 17:51:11/
文章来源:
做视频网站软件,长春网站制作设计,免费制作网站和网页,三语网站建设1. 单例模式 单例模式是一种设计模式#xff0c;设计模式是我们必须要掌握的一个技能#xff1b;
1.1 关于框架和设计模式 设计模式是软性的规定#xff0c;且框架是硬性的规定#xff0c;这些都是技术大佬已经设计好的#xff1b; 一般来说设计模式有很多种#xff0c;…1. 单例模式 单例模式是一种设计模式设计模式是我们必须要掌握的一个技能
1.1 关于框架和设计模式 设计模式是软性的规定且框架是硬性的规定这些都是技术大佬已经设计好的 一般来说设计模式有很多种且不同的语言会有不同的设计模式同时设计模式也可以理解为对编程语言的一种补充
1.2 细说单例模式 单例 单个实例对象 某个类在一个线程中只应该创建一个实例化对象原则上不应该有多个这时就使用单例模式如此可以对我们的代码进行一个更严格的校验和检查。 保证对象唯一性的方法 方法一可以通过“协议约束”写一个文档规定这个类只能有唯一的实例程序员在接手这个代码时就会发现这个文档已经进行约定其中的规定约束着程序员在创建对象时时刻注意只能创建一个对象。 方法二从机器入手让机器帮我们检查我们期望让机器帮我们对代码中指定的类创建类的实例个数进行检查、校验当创建的实例个数超过我们期望个数就编译报错。其中单例模式就是已经设计好的套路可以实现这种预期效果。 关于单例模式代码实现的基本方式有两种饿汉模式和懒汉模式
2. 饿汉模式 饿汉模式是指创建实例的时期非常早在类加载的时候程序一启动就已经创建好实例了使用 “饿汉”这个词就是形容创建实例非常迫切非常早。单例模式代码如下
class Singleton {private static Singleton instance new Singleton();public static Singleton getInstance() {return instance;}private Singleton(){ }
}
public class TestDemo4 {public static void main(String[] args) {Singleton singleton new Singleton();}
} 当我们运行该代码时系统就会报错接下来我们详细的分析一下此处的代码 这样如果我们想new一个Singleton对象也new不了同时不管我们用getInstance获取多少次实例获取的对象都是同一个对象代码如下
package thread;// 就期望这个类只能有唯一的实例 (一个进程中)
class Singleton {private static Singleton instance new Singleton();public static Singleton getInstance() {return instance;}private Singleton() {}
}public class ThreadDemo26 {public static void main(String[] args) {// Singleton s new Singleton();Singleton s Singleton.getInstance();Singleton s2 Singleton.getInstance();System.out.println(s s2);}
}结果如下 3. 懒汉模式 和饿汉模式不一样的是懒汉模式创建实例的时机比较晚没饿汉创建实例那么迫切只有第一次使用这个类时才会创建实例代码如下
class SingletonLazy {private static SingletonLazy instance null;public static SingletonLazy getInstance() {if(instance null) {instance new SingletonLazy();}return instance;}private SingletonLazy() { }
}
public class TestDemo5 {public static void main(String[] args) {}
} 下面为代码图解分析 和饿汉模式的区别就是没那么迫切创建实例等需要调用这个类的时候才创建一个实例而饿汉模式是有了这个类就创建出实例。 懒汉模式的优点有的程序要在一定条件下才需要进行相关的操作有时候不满足这个条件也就不需要完成这个操作了如此哦·就把这个操作省下来了。
4. 两种模式关于线程安全
4.1 饿汉模式 线程安全 对于饿汉模式来说上图所示通过调用getinstance方法来返回instance对象本质上来说是读操作 当有多个线程同时并发执行调用getInstance方法取instance这时线程是安全的因为只涉及到读多线程读取同一个变量是线程安全的。而instance很早之前就已经创建好了不会修改它一直也只有这一个实例也不涉及写的操作。
4.2 懒汉模式 线程不安全 在懒汉模式中条件判定和返回时是读操作new一个对象是写操作 我们只有调用getInstance方法后就会创建出实例来如果多个线程同时调用这个方法此时SingletonLazy类里面的instance都为null那么这些线程都会new对象就会创建多个实例。这时就不符合我们单例模式的预期了所以这个代码是线程不安全的。 线程不安全的直接原因就是 “写” 操作不是原子的。
4.3 解决懒汉模式的线程安全问题
4.3.1 把写操作打包成原子 因为多线程并发执行的时候可能读到的都是instance null所以会创建多个实例那我们就给它加锁让它在创建实例的时候只能创建一个加锁代码如下
class SingletonLazy {private static Object locker new Object();private static SingletonLazy instance null;public static SingletonLazy getInstance() {synchronized (locker) {if(instance null) {instance new SingletonLazy();}}return instance;}private SingletonLazy() { }
} 以上操作虽然将写操作打包成了一个原子但是新的问题也出现了
4.3.2 去除冗余操作 上述操作加上了还是有问题如果已经创建出实例了我们还有加锁来判断它是不是null吗加锁这些操作也是要消耗硬件资源的没有必要为此浪费资源空间如果已经不是null了我们就想让它直接返回不再进行加锁操作代码修改如下
class SingletonLazy {private static Object locker new Object();private static SingletonLazy instance null;public static SingletonLazy getInstance() {if (instance null) {synchronized (locker) {if (instance null) {instance new SingletonLazy();}}}return instance;}private SingletonLazy() { }
} 代码图解分析两个判断语句的是目的意义 4.3.3 指令重排序的问题 指令重排序指令重排序也是编译器的一种优化在保证原代码的逻辑不变调整原代码的指令执行顺序从而让程序的执行效率提高。 保证原代码的逻辑不变改变原有指令的顺序从而提高代码的执行效率其中这个代码就存在着指令重排序的优化如下图代码 该语句原本指令执行顺序 1、去内存申请一段空间 2、在这个内存中调用构造方法创建实例 3、从内存中取出地址赋值给这个实例instance。 指令重排序后的顺序1, 3 , 2按照指令重排序后的代码执行逻辑就变成了下面所示 假设有两个线程现在执行顺序如下图所示 因为指令重排序后先去内存申请一段空间然后是赋值给instance那这时instance就不是null了第二个线程不会进入到if语句了直接返回instance可是instance还没有创建出实例这样返回肯定是有问题的如此也就线程不安全了。 解决方案 给instance这个变量加volatile修饰强制取消编译器的优化不能指令重排序同时也排除了内存可见性的问题。 加volatile后的代码如下 class SingletonLazy {private static Object locker new Object();private static volatile SingletonLazy instance null;public static SingletonLazy getInstance() {if (instance null) {synchronized (locker) {if (instance null) {instance new SingletonLazy();}}}return instance;}private SingletonLazy() { }
} 至此我们才算解决掉懒汉模式关于线程安全的所有问题 4.4 懒汉模式线程安全的代码
package thread;// 懒汉的方式实现单例模式.
class SingletonLazy {// 这个引用指向唯一实例. 这个引用先初始化为 null, 而不是立即创建实例private volatile static SingletonLazy instance null;private static Object locker new Object();public static SingletonLazy getInstance() {// 如果 Instance 为 null, 就说明是首次调用, 首次调用就需要考虑线程安全问题, 就要加锁.// 如果非 null, 就说明是后续的调用, 就不必加锁了.if (instance null) {synchronized (locker) {if (instance null) {instance new SingletonLazy();}}}return instance;}private SingletonLazy() { }
}public class ThreadDemo27 {public static void main(String[] args) {SingletonLazy s1 SingletonLazy.getInstance();SingletonLazy s2 SingletonLazy.getInstance();System.out.println(s1 s2);}
}结果如下 ps:本次的内容就到这里了如果感兴趣的话就请一键三连哦
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/83449.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!