8种单例模式写法助你搞定面试
:1. 单例模式常见问题
为什么要有单例模式
单例模式是一种设计模式,它限制了实例化一个对象的行为,始终至多只有一个实例。当只需要一个对象来协调整个系统的操作时,这种模式就非常有用.它描述了如何解决重复出现的设计问题,
比如我们项目中的配置工具类,日志工具类等等。
如何设计单例模式 ?
1.单例类如何控制其实例化
2.如何确保只有一个实例
通过一下措施解决这些问题:
private构造函数,类的实例话不对外开放,由自己内部来完成这个操作,确保永远不会从类外部实例化类,避免外部随意new出来新的实例。
该实例通常存储为私有静态变量,提供一个静态方法,返回对实例的引用。如果是在多线程环境下则用锁或者内部类来解决线程安全性问题。
2. 单例类有哪些特点 ?
私有构造函数
它将阻止从类外部实例化新对象
它应该只有一个实例
这是通过在类中提供实例来方法完成的,阻止外部类或子类来创建实例。这是通过在java中使构造函数私有来完成的,这样任何类都不能访问构造函数,因此无法实例化它。
单实例应该是全局可访问的
单例类的实例应该是全局可访问的,以便每个类都可以使用它。在Java中,它是通过使实例的访问说明符为public来完成的。
节省内存,减少GC
因为是全局至多只有一个实例,避免了到处new对象,造成浪费内存,以及GC,有了单例模式可以避免这些问题
3. 单例模式8种写法
下面由我给大家介绍8种单例模式的写法,各有千秋,存在即合理,通过自己的使用场景选一款使用即可。我们选择单例模式时的挑选标准或者说评估一种单例模式写法的优劣时通常会根据一下两种因素来衡量:
1.在多线程环境下行为是否线程安全
2.饿汉以及懒汉
3.编码是否优雅(理解起来是否比较直观)
1. 饿汉式线程安全的
public class SingleTon{
//私有 static final的
private static final SingleTon INSTANCE = new SingleTon();
//私有构造器
private SingleTon(){ }
public static SingleTon getInstance(){
return INSTANCE; }
public static void main(String[] args) { SingleTon instance1 = SingleTon.getInstance(); SingleTon instance2 = SingleTon.getInstance(); System.out.println(instance1 == instance2); } }
这种写法是非常简单实用的,值得推荐,唯一缺点就是懒汉式的,也就是说不管是否需要用到这个方法,当类加载的时候都会生成一个对象。
除此之外,这种写法是线程安全的。类加载到内存后,就实例化一个单例,JVM保证线程安全,
2. 饿汉式线程安全(变种写法)。
public class SingleTon{
private static final SingleTon INSTANCE ;
static { INSTANCE = new SingleTon(); }
private SingleTon(){}
public static SingleTon getInstance(){
return INSTANCE; }
public static void main(String[] args) { SingleTon instance1 = SingleTon.getInstance(); SingleTon instance2 = SingleTon.getInstance(); System.out.println(instance1 == instance2); } }
3. 懒汉式线程不安全。
public class SingleTon{
private static SingleTon instance ;
private SingleTon(){}
public static SingleTon getInstance(){
if(instance == null){ instance = new SingleTon(); }
return instance; }
public static void main(String[] args) { SingleTon instance1 = SingleTon.getInstance(); SingleTon instance2 = SingleTon.getInstance(); System.out.println(instance1 == instance2); // 通过开启100个线程 比较是否是相同对象 for(int i=0;i<100;i++){ new Thread(()-> System.out.println(SingleTon.getInstance().hashCode()) ).start(); } } }
这种写法虽然达到了按需初始化的目的,但却带来线程不安全的问题,至于为什么在并发情况下上述的例子是不安全的呢 ?
// 通过开启100个线程 比较是否是相同对象
for(int i=0;i<100;i++){
new Thread(()-
原创不易,完成人机校验,阅读全文