当前位置: 首页 > news >正文

网页美工设计素材谷歌seo外包

网页美工设计素材,谷歌seo外包,网页网站建设,菡萏怡景装饰公司🎍目录 ⛳ 面试题-单例模式会存在线程安全问题吗?🎨 一、单例模式-简介🚜 二、饿汉式🐾 三、懒汉式🎯 3.1、懒汉式:在调用 getInstance 的时候才创建对象。(线程不安全)&…

🎍目录

  • ⛳ 面试题-单例模式会存在线程安全问题吗?
    • 🎨 一、单例模式-简介
    • 🚜 二、饿汉式
    • 🐾 三、懒汉式
      • 🎯 3.1、懒汉式:在调用 getInstance 的时候才创建对象。(线程不安全)
      • 🏓 3.2、改造1:对懒汉式进行加锁改造(线程安全)
      • 🔮 3.3、改造2:对懒汉式继续改造。(线程不安全)
      • 🏀 3.4、改造3(改造成功):对懒汉式再次改造。(线程安全)
      • 3.5、总结
    • 🏭 四、内部静态类
      • 🧰 4.1、反射攻击
      • 🧬 4.2、反序列化攻击
    • ⭐ 五、枚举
    • 📢 六、总结

⛳ 面试题-单例模式会存在线程安全问题吗?

答:会出现线程安全问题。

首先,在Java中创建单例实例的方式有:饿汉式、懒汉式、静态内部类、枚举等方式;

饿汉模式是天生线程安全的,饿汉模式在类创建的同时,就创建好了一个静态对象,又因为静态变量只会在类创建时执行一次,所以创建好的实例不会再改变,因此是线程安全的。

懒汉式不是线程安全的,当多并发情形下,可能会多个线程都创建实例,不能保证单例模式,可以改成双重校验锁,既保证了调用效率,又保证了线程安全。

静态内部类的方式相比于懒汉模式的优势是可以延迟加载,因为只有在静态内部类被调用时,JVM才会加载它,同时保证了线程安全和调用效率。

以上三种的创建方式都不能解决,反射、反序列化产生的线程安全问题;

使用枚举天然的防止反射和反序列化,既保证了线程安全,又保证了调用效率,但是不能延时加载;

🎨 一、单例模式-简介

单例模式是 Java 中常用的设计模式之一,属于设计模式三大类中的创建型模式。在运行期间,保证某个类仅有一个实例,并提供一个访问它的全局访问点。单例模式所属类的构造方法是私有的,所以单例类是不能被继承的。实现线程安全的单例模式有以下几种方式有:饿汉式、懒汉式、懒汉式改良版(双重同步锁),内部静态类、枚举;

🚜 二、饿汉式

天生是线程安全的 !(但是无法应对反射、序列化的形式)

饿汉式在类创建的同时,就已经创建好了一个静态的对象供系统使用,以后不在改变;

public class Singleton {private static Singleton instance = new Singleton();private Singleton() {  // 私有的构造方法}public static Singleton getInstance() {return instance;}}

这是实现一个安全的单例模式的最简单粗暴的写法,所以称之为饿汉式;

因为肚子饿了,想要马上吃到东西,不想等待生产时间。在类被加载的时候就把 Singleton 实例给创建出来,以后不在改变。

饿汉式的优点和缺点:

  • 优点:实现简单、线程安全,调用效率高(无锁,且对象在类加载时就已创建,可直接使用);
  • 缺点:可能在还不需要此实例的时候就已经把实例创建出来了,不能延时加载(在需要的时候才创建对象)、使用反射,序列化创建对象依然可以不是单例的;

🐾 三、懒汉式

🎯 3.1、懒汉式:在调用 getInstance 的时候才创建对象。(线程不安全)

public class Singleton {  private static Singleton instance=null;  private Singleton() {};  public static Singleton getInstance(){  if(instance==null){//可能会有多个线程进入代码块,造成实例化多个对象instance=new Singleton();  }  return instance;  }  }

🏓 3.2、改造1:对懒汉式进行加锁改造(线程安全)

public class Singleton {  private static Singleton instance=null;  private Singleton() {};  public static synchronized Singleton getInstance(){  if(instance==null){  instance=new Singleton();  }  return instance;  }  
}

但是这种方式并不推荐,因为效率想对较低,每个线程在执行 getInstance 的时候都要进行同步。而如果 instance 已经实例化了可以直接返回,还需要进行改造;

🔮 3.3、改造2:对懒汉式继续改造。(线程不安全)

public class Singleton {  private static Singleton instance=null;  public static Singleton getInstance() {  if (instance == null) {  synchronized (Singleton.class) {  instance = new Singleton();  }  }  return instance;  }  
}

这种方式是线程不安全的,假如 A,B 两个线程同时进入到了 if(instance == null)的代码块, A 线程拿到了锁进入 synchronized代码块,对 instance 进行实例化,结束并释放锁,B 线程便拿到锁,依然会进入到 synchronized代码块对 instance 进行实例化。那么这就对 instance 进行了两次实例化。出现了线程安全的问题。

🏀 3.4、改造3(改造成功):对懒汉式再次改造。(线程安全)

这种代码书写方式也称为 双重同步锁

public class Singleton {  private static volatile Singleton instance=null;  private Singleton(){}public static Singleton getInstance() {  if (instance == null) {  synchronized (Singleton.class) { //在(3.3)的基础上多了一次判断,避免了线程安全问题if (instance == null) {  instance = new Singleton();  }}  }  return instance;  }  
}

使用了double-check即check-加锁-check,减少了同步的开销;

在创建第一个对象时候,可能会有线程1,线程2两个线程进入getInstance()方法,这时对象还未被创建,所以都通过第一层check。接下来的synchronized锁只有一个线程可以进入,假设线程1进入,线程2等待。线程1进入后,由于对象还未被创建,所以通过第二层check并创建好对象,由于对象singleton是被volatile修饰的,所以在对singleton修改后会立即将singleton的值从其工作内存刷回到主内存以保证其它线程的可见性。线程1结束后线程2进入synchronized代码块,由于线程1已经创建好对象并将对象值刷回到主内存,所以这时线程2看到的singleton对象不再为空,因此通过第二层check,最后获取到对象。这里volatile的作用是保证可见性,同时也禁止指令重排序,因为上述代码中存在控制依赖,多线程中对控制依赖进行指令重排序会导致线程不安全。

优点:线程安全,可以延时加载,调用效率比锁加在方法上高。

另外,需要注意 instance采用 volatile 关键字修饰也是很有必要。

  • instance采用 volatile 关键字修饰也是很有必要的, instance = new Singleton();
    这段代码其实是分为三步执行:
    1. 为 instance 分配内存空间;
    2. 初始化 instance ;
    3. 将 instance 指向分配的内存地址;

但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1->3->2。指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。

使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行

3.5、总结

相比于饿汉式,懒汉式显得没那么 “饿”,在真正需要的时候在去创建实例。

懒汉式的优点和缺点:

  • 优点:线程安全的,可以延时加载。
  • 缺点:调用效率不高(有锁,且需要先创建对象)、使用反射,序列化创建对象依然可以不是单例的

🏭 四、内部静态类

public class Singleton {private Singleton() {}public static Singleton getInstance() {return SingletonFactory.instance;}private static class SingletonFactory {private static Singleton instance = new Singleton();}
}    

静态内部类只有被主动调用的时候,JVM才会去加载这个静态内部类。外部类初次加载,会初始化静态变量、静态代码块、静态方法,但不会加载内部类和静态内部类。

优点:线程安全,调用效率高,可以延时加载。

似乎静态内部类看起来已经是最完美的方法了,其实不是,可以还存在反射攻击和反序列化攻击。

🧰 4.1、反射攻击

public class Singleton {private Singleton() {}public static Singleton getInstance() {return SingletonFactory.instance;}private static class SingletonFactory {private static Singleton instance = new Singleton();}public static void main(String[] args) throws Exception {Singleton singleton = Singleton.getInstance();Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();constructor.setAccessible(true);Singleton newSingleton = constructor.newInstance();System.out.println(singleton == newSingleton);
}}  

运行结果:false

通过结果看,这两个实例不是同一个,违背了单例模式的原则;

🧬 4.2、反序列化攻击

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.8.1</version>
</dependency>

这个依赖提供了序列化和反序列化工具类。

Singleton 类实现了 java.io.Serializable接口。

public class Singleton implements Serializable {private static class SingletonHolder {private static Singleton instance = new Singleton();}private Singleton() {}public static Singleton getInstance() {return SingletonHolder.instance;}public static void main(String[] args) {Singleton instance = Singleton.getInstance();byte[] serialize = SerializationUtils.serialize(instance); // 序列化为一个数组Singleton newInstance = SerializationUtils.deserialize(serialize); // 通过刚才序列化的数组,进行反序列化System.out.println(instance == newInstance);}}

输出结果:false,表示不是一个实例;

如果要解决 Singleton 类的实力在序列化和反序列化过程中仍然是唯一的,需要添加一个readResolve()方法到 Singleton 类中,以便在反序列化是返回相同的实例。如:

private Object readResolve() throws ObjectStreamException {return getInstance();
}

在 Java 中,readResolve() 方法是一个特殊的方法,用于在对象反序列化过程中控制返回的实例。它主要用于解决单例模式在反序列化时可能出现的问题。

⭐ 五、枚举

最佳的单例实现模式就是枚举模式。写法简单,线程安全,调用效率高,可以天然的防止反射和反序列化调用,不能延时加载。

public enum Singleton {INSTANCE;public void doSomething() {System.out.println("doSomething");}
}    

调用方法:

public class Main {public static void main(String[] args) {Singleton.INSTANCE.doSomething();}}

直接通过Singleton.INSTANCE.doSomething()的方式调用即可。

枚举如何实现线程安全?反编译后可以发现,会通过一个类去继承该枚举,然后通过静态代码块的方式在类加载时实例化对象,与饿汉类似。https://blog.csdn.net/wufaliang003/article/details/81395411

如何做到防止反序列化调用?每一个枚举类型及其定义的枚举变量在JVM中都是唯一的,Java做了特殊的规定,枚举类型序列化和反序列化出来的是同一个对象。

除此之外,枚举还可以防止反射调用。

📢 六、总结

综上,线程安全的几种单例模式比较来看:

枚举(无锁,调用效率高,可以防止反射和反序列化调用,不能延时加载)> 静态内部类(无锁,调用效率高,可以延时加载)> 双重同步锁(有锁,调用效率高于懒汉式,可以延时加载)> 懒汉式(有锁,调用效率不高,可以延时加载)~= 饿汉式(无锁,调用效率高,不能延时加载)

注:只有枚举类型能防止反射和反序列化;

http://www.khdw.cn/news/62951.html

相关文章:

  • 西安网站制作公司怎么选app拉新推广怎么做
  • 蜘蛛爬网站网站宣传的方法有哪些
  • 网站开发课表查询热门搜索排行榜
  • java 网站开发开什么书广告推广媒体
  • 怎么做动态网站的数据库武汉推广服务
  • 做马甲的网站seo网站怎么优化
  • 网站建设能够不同地方新网络营销
  • 科技有限公司名称大全关键词优化软件排行
  • 培训公司网站源码seo快排软件
  • 报电子商务(网站建设与运营)最新疫情最新消息
  • 建设网站需要注意什么北京网站推广服务
  • 微信网站制作价格网络流量分析工具
  • 做微信的网站有哪些功能泰州百度seo
  • 网站开发技术报告模板搜索百度下载安装
  • 网站开发 一个页面多少钱网页设计与制作学什么
  • 网页设计试题及答案seo搜索优化工具
  • 做彩票网站是违法吗汕头网站建设开发
  • 南宁企业建站系统模板百度搜索推广费用
  • 网站备案要求企业 个人浏览器2345网址导航下载安装
  • wordpress小程序配置广州seo网站管理
  • 怎么用手机做网站网络营销师证书需要多少钱
  • 家庭带宽100m做网站google play
  • 福州网上商城网站建设北海seo快速排名
  • 公司建设网站请示软文是什么意思?
  • 网站热区图品牌策划包括哪几个方面
  • 网站开发需求分析的内容广告网站推荐
  • 做网贷网站歌尔股份砍单
  • 一网学网站是真的吗天津做网站的
  • java可以做网站么seo的中文含义是什么
  • 免费中文企业网站模板怎么做百度关键词排名