有没有正规的毕设代做网站,wordpress分类目录keyword,建设公司上市企业有多少?,网站内链如何布局文章目录 单例模式一、单例模式1.饿汉模式2.懒汉模式#xff08;单线程#xff09;3.懒汉模式#xff08;多线程#xff09;改进 4.指令重排序1.概念2.question:3.解决方法4总结#xff1a; 单例模式 一、单例模式
单例#xff0c;就是单个实例 在有些场景中#xff0c… 文章目录 单例模式一、单例模式1.饿汉模式2.懒汉模式单线程3.懒汉模式多线程改进 4.指令重排序1.概念2.question:3.解决方法4总结 单例模式 一、单例模式
单例就是单个实例 在有些场景中希望有的类只能有一个对象通过代码的语法规范达到编译器强制检查的效果 单例模式保证某个类在程序中只存在唯一一份实例, 而不会创建出多个实例
比如很多用来管理数据的对象就是单个实例的。
1.饿汉模式
//希望有唯一实例
class Singleton {//单例模式private static Singleton instance new Singleton();//因为是static成员在Singleton这个类被加载的时候这里就会创建实例public static Singleton getInstance(){//通过getInstance方法来获取到这个实例return instance;}private Singleton(){}//将构造方法设置为私有的}public static void main(String[] args) {Singleton instance1 Singleton.getInstance();//通过类名调用成员方法获取到唯一实例Singleton instance2 Singleton.getInstance();System.out.println(instance1 instance2);//true}将构造方法设置为私有的避免再次生成实例。只能通过getInstance()方法来获取类变量创建好的唯一实例唯一实例是在类加载的时候创建的创建时间早-饿汉模式比较急在饿汉模式中如果在多线程中多个线程同时读取同一个变量是线程安全的。只读不修改。
2.懒汉模式单线程
比较从容在第一次使用的时候再去创建实例
class SingletonLazy{private static SingletonLazy instance null;//先设置为空public static SingletonLazy getInstance(){if (instance null){instance new SingletonLazy();}return instance;}private SingletonLazy(){}}在首次调用getInstance方法的时候才会真正创建唯一实例 不调用就不会创建。 ”懒“意味着高效省略不必要的操作和开销只在需要的时候才开始进行。 违背了单例的要求。懒汉模式在多线程环境下涉及到了同一个变量的读取和修改就存在线程安全问题。
3.懒汉模式多线程
解决方法对if的判断操作和创建实例操作进行加锁使两个操作始终执行在一起。
class SingletonLazy{private static SingletonLazy instance null;//先设置为空public static SingletonLazy getInstance(){synchronized(SingletonLazy.class){if (instance null){instance new SingletonLazy();}}return instance;}private SingletonLazy(){}
}虽然进行了加锁但是每次再调用getInstance()方法的时候都会进行加锁操作。而懒汉模式的线程安全问题体现在第一次实例法创建。后续创建好实例后的所有调用操作都是读操作没有必要进行加锁。加锁是一个开销很大的操作加锁就可能涉及到锁竞争一冲突就会引发堵塞等待涉及线程的调度。
改进
在加锁操作前再进行一次判断
如果实例未创建此时存在线程安全问题需要加锁。如果对象已经创建此时线程就是安全的不需要加锁 private static SingletonLazy instance null;//先设置为空public static SingletonLazy getInstance() {if (instance null) {//第一个if判断的是是否要加锁synchronized (SingletonLazy.class) {if (instance null) {//第二个if判断的是是否要new对象instance new SingletonLazy();}}}return instance;}首次拿到锁的那个进程一定创建了这个唯一对象。等后续的进程拿到锁后再次进行判断就不会创建对象了。 指令重排序可能会对上述代码会产生影响。 4.指令重排序
1.概念
同样也是因为编译器的优化
编译器为了执行效率在保证逻辑不变的前提下可能会调整原来代码的执行顺序从而提高效率。 在单线程下安全多线程下可能会存在误判。 在多线程下创建实例的操作时new操作可能会引发指令重排序问题
new操作分为三步第一步一定是先执行的可能是1 、2、3 或者1、3、2的顺序来执行。 1.申请内存空间 2.在内存空间上构造对象执行构造方法 3.把内存的地址赋值给instance引用 就类似于买房 装修 交钥匙 / 买房、交钥匙、装修 最终效果是一样的。
假设线程1按照1、3、2的顺序来执行。当1和3执行完后3直接进行赋值操作。此时instance就不在是null了而是指向的是一个还没有进行初始化的非法对象。此时1、3执行完还没开始执行操作2线程2就开始执行了 。线程2先对instance进行判断。此时intancenull 不成立线程2直接返回instance。但是instance只是一个还没有进行初始化的非法对象。线程2获取的对象是不完全的。会产生严重的问题。
也就是说由于操作指令的执行顺序被优化了导致实例创建的不完全就被调用了。表面提前符合了判断标准但是内部还没有进行完全。就类似于业主买的是精装房直接交了钥匙想要拎包入住时发现没有进行装修还是毛坯房。实际上精装房是包含装修的。那么就是开发商的执行顺序出现了问题没安排装修就交了钥匙~
2.question:
提问既然线程1执行到new的过程中就已经先加锁了。线程2还能new的1、3操作刚完时就插进来执行吗
因为线程2的第一个if没有涉及到加锁操作是完全可以执行的。锁的阻塞等待一定是两个线程都加锁的时候才会触发。线程1拿到锁时修改了instance的引用。此时线程2并没有参与锁的竞争只是进行了第一个if的判断非空情况下也不会进入if内部进行加锁操作而是直接进行了返回。因此没有涉及任何阻塞等待。
3.解决方法
采用volatile,用volatile来修饰instence,保证instence在修改的过程中就不会进行指令重排序的现象了。
class SingletonLazy {private static volatile SingletonLazy instance null;//先设置为空public static SingletonLazy getInstance() {if (instance null) {//第一个if判断的是是否要加锁synchronized (SingletonLazy.class) {if (instance null) {//第二个if判断的是是否要new对象instance new SingletonLazy();}}}return instance;}private SingletonLazy() {}
4总结
单例模式三步走
1.懒汉模式下的双重if嵌套
2.用Synchronized对第二个if和后续是实例化操作进行加锁
3.用volatile修饰实例禁止指令重排序。
面试遇到的话人生如戏全靠演技要适当藏拙一步一步优化。从单线程的懒汉模式到加锁再到指令重排序
点击移步博客主页欢迎光临~