JAVA就业面试题 4.1单例模式
单例,就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时确保只有一个对象被创建。
特点
持有自己类型的属性
类构造器私有
对外提供获取实例的静态方法
4.1.1 懒汉式
/**
- Created by 张晨光 on 2020/6/12 11:07
- 懒汉式 */ public class Banzhang { //1.自己类的静态属性 private static Banzhang bz; //2.私有的构造方法 private Banzhang(){} //3.提供对外获取实例的静态方法 public static Banzhang getInstance(){ if(bz==null) bz= new Banzhang(); return bz; } }
问题,线程不安全,延迟初始化,问题在 12行; 4.1.2 饿汉式
线程安全,比较常用,但容易产生垃圾,因为一开始就初始化
/**
- Created by 张晨光 on 2020/6/12 11:12
- 饿汉式 */ public class SingleTon { //1.静态自己本身属性; private static SingleTon singleTon=new SingleTon(); //2.私有构造方法; private SingleTon(){} //3.提供静态的方法实例; public static SingleTon getInstance(){ return singleTon; } }
饿汉式:立即加载;
懒汉式:延迟加载;–》节省资源 4.1.3 双重锁模式
双重检查模式,进行了两次的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于singleton=new Singleton()对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile修饰signleton实例变量有效,解决该问题。
/**
- Created by 张晨光 on 2020/6/12 11:22
- 双重锁模式 */ public class Monitor { private volatile static Monitor monitor; private Monitor(){} private static Monitor getInstance(){ if(monitor==null){ synchronized (Monitor.class){ if(monitor==null) monitor=new Monitor(); } } return monitor; } }
4.1.4 静态内部类
只有第一次调用getInstance方法时,虚拟机才加载 Inner 并初始化instance ,只有一个线程可以获得对象的初始化锁,其他线程无法进行初始化,保证对象的唯一性。目前此方式是所有单例模式中最推荐的模式,但具体还是根据项目选择。
/**
- Created by 张晨光 on 2020/6/12 11:29
- 静态内部类 */ public class JtSingleTon { //private static JtSingleTon jtSingleTon; private JtSingleTon(){} private static JtSingleTon getInstance(){ return Inner.jtSingleTon; } private static class Inner{ private static final JtSingleTon jtSingleTon=new JtSingleTon(); } }
4.1.5 枚举实现
首先是再了解一下枚举
/**
- Created by 张晨光 on 2020/6/12 15:36
- 枚举测试;先来理解枚举的原理; */ public enum EnumSingleTon { INSTANCE; //关键字; private EnumSingleTon(){ System.out.println("初始化..."); } public static EnumSingleTon getInstance(){ return INSTANCE; } }
使用枚举的这种,只初始化一次的特征,来实现单例。
package single;
/**
- Created by 张晨光 on 2020/6/12 15:42
- User类,使用枚举实现; */ public class User { //1.私有的构造方法; private User(){} //2.利用枚举类来获取实例;在这里放一个枚举SingleTon static enum SingleTon{ //有一个枚举对象,天生为单例; INSTANCE; private User user; //私有的枚举构造方法;只被初始化一次; private SingleTon(){ user=new User(); } //由枚举提供一个获取User类的实例方法 public User getInstance(){ return user; } } //3.通过枚举来获取单例; public static User getInstance(){ return SingleTon.INSTANCE.getInstance(); } }
//调用测试方法,来测试User类是否单例的实现; @Test public void testEnumUser(){ User est1=User.getInstance(); User est2=User.getInstance(); System.out.println(est1); System.out.println(est2); }
总结:
1.理解:单例的概念
2.了解:懒汉式和饿汉式;建议会写静态内部类的实现;
用枚举类来获取实例;在这里放一个枚举SingleTon static enum SingleTon{ //有一个枚举对象,天生为单例; INSTANCE; private User user; //私有的枚举构造方法;只被初始化一次; private SingleTon(){ user=new User(); } //由枚举提供一个获取User类的实例方法 public User getInstance(){ return user; } } //3.通过枚举来获取单例; public static User getInstance(){ return SingleTon.INSTANCE.getInstance(); } }
//调用测试方法,来测试User类是否单例的实现;
@Test
public void testEnumUser(){
User est1=User.getInstance();
User est2=User.getInstance();
System.out.println(est1);
System.out.println(est2);
}
9
10
总结:
1.理解:单例的概念
2.了解:懒汉式和饿汉式;建议会写静态内部类的实现;
3.其他的知道即可,根据自己的程度,看看就行了。
————————————————