java笔试题:实现单例模式⽂章⽬录
单例模式的实现
java单例模式的实现分为五种:
饿汉模式(线程安全)
懒汉模式(线程不安全,但是可以修改,不建议使⽤,延迟加载)
DCL双检查锁机制(线程安全,延迟加载)
静态内部类实现(线程安全,但是遇见序列化对象时会出现多实例情况,延迟加载)
枚举类实现(线程安全,不会出现序列化带来的问题,延迟加载)
1. 饿汉模式
单例模式的几种实现方式优点:单例在类被加载的时候被创建,线程安全,可以⽤于多线程环境
缺点:如果单例未被使⽤,那么同样会被创建,会造成内存浪费
/
**
* 饿汉模式
* 在调⽤前就已经创建,可能会浪费内存
*/
public class Singleton1 {
//设置为私有防⽌其他对象调⽤
private Singleton1 (){};
private static Singleton1 instance = new Singleton1();
public static Singleton1 getInstance(){
return instance;
}
}
2. 懒汉模式
优点:在需要被使⽤的时候才被创建,不会造成资源浪费
缺点:线程不安全,getInstance⽅法没有同步,在多线程的情况下会造成创建的实例不同线程安全的修改⽅法:
使⽤synchronized关键字同步getInstance⽅法
使⽤synchronized关键字同步代码块
但是这两种修改⽅法会使代码的效率变的很低,所以不推荐使⽤
/**
* 懒汉模式⾮线程安全通过添加synchronized关键字来同步getInstance⽅法
* 解决懒汉模式:同步getInstance⽅法同步代码块
*/
public class Singleton2 {
private Singleton2(){};
private static Singleton2 instance = null;
public static Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}
3. DCL双检查锁机制
线程安全,延时加载
双检查锁机制就是进⾏第⼆次检查,也就是代码中两次判断null的操作,但是为什么要这样呢?
特殊情况的出现:
线程ThreadA,ThreadB,如果threadA执⾏到了第⼀个if条件判断,instance = null;ThreadB也执⾏到了if条件判断instance = null,所以A和B会依次执⾏同步代码块⾥的代码。为了避免创建两个实例,因此⼜在同步代码块⾥添加了if条件进⾏⼆重检验。
但是由于会出现指令重排序的问题,这样还会导致线程不安全的情况,所以添加了volatile 关键字
volatile 关键字作⽤:
禁⽌指令重排序
同步内存,每次修改值之后必须⽴即刷新到主存,线程取的时候也是从主存取
/**
- 双重锁机制
- 要注意判断两次null
*/
public class Singleton3 {
private Singleton3(){};
public volatile static Singleton3 instance = null;
public static Singleton3 getInstance(){
if(instance == null){
synchronized (Singleton3.class){
if(instance == null){
instance = new Singleton3();
}
}
}
return instance;
}
}
4. 静态内部类实现
线程安全,延时加载
由于内部类是隐藏的,所以只要不使⽤内部类,那么JVM就不会将其加载进来,这样就很好的实现了延迟加载
缺点:遇到序列化对象的时候,如果还使⽤默认的运⾏⽅式,就会出现多实例的情况,解决⽅法是在反序列化中使⽤readResolve⽅法为什么是线程安全的:虚拟机会保证⼀个类的构造器⽅法在多线程环境中被正确地加载,同步,如果多个线程同时去初始化⼀个类,那么只有⼀个线程去执⾏这个类的
public class Singleton4 {
private Singleton4(){};
private static class SingleHolder{
private static Singleton4 instance = new Singleton4();
}
public static Singleton4 getInstance(){
return SingleHolder.instance;
}
}
5. 枚举类实现
由于很不常见,所以了解即可
public enum ExSingleton {
INSTANCE;
public void someMethod(){
}
}
6.总结
总的来说双重锁机制和静态内部类机制是推荐使⽤的,双重锁机制是⼀般多线程情况下的实现选择
在⾯试的时候可以选择写静态内部类实现和DCL双重锁机制实现,但是书写的过程都是类似的:
DCL双重锁:
⾸先声明私有的构造函数
再定义私有的静态实例,并且使⽤ volatile 关键字修饰
实现getInstance静态⽅法,先进⾏第⼀次检查,之后实现synchronized同步代码块,在其中实现第⼆次检查,进⾏
instance赋值
最后return instance
静态内部类:
⾸先声明私有构造函数
再定义静态内部类,其中定义私有静态实例并创建
实现getInstance静态⽅法,返回静态内部类中的实例
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论