JAVA程序员必须理解的单例模式

JAVA设计模式之一单例模式

单例模式

首先我们要知道什么是单例模式,单例模式的用法以及好处

  1. 单例模式,顾名思义就是只加载一个实例
  2. 好处,别的不说没有并发性,不需要考虑线程安全,安全私有化不能随意去实例
  3. 用法有好几个,分别是饿汉式,懒汉式,饿汉改进式等

饿汉式 SingletonDemo01.java

效率高,不能延时加载

package 单例模式;
//饿汉式单例
public class SingletonDemo01 {
   //1.私有化构造器
 private SingletonDemo01() {}
   //2.类的初始化的时候立即加载对象,不管用不用全都要所以很,不用考虑并发性线程安全
 private static SingletonDemo01 instance=new SingletonDemo01();
   //提供获取该对象的方法,没有synchronized,效率高
 public static SingletonDemo01 getInstance() {
  return instance;
 }
}
class Test{
 public static void main(String[] args) {
  // TODO 自动生成的方法存根
       SingletonDemo01 instance=SingletonDemo01.getInstance();
       SingletonDemo01 instance2=SingletonDemo01.getInstance();
       System.out.print(instance==instance2); //true,的确是单例
 }
}

使用场景:对象功能简单且使用对象次数少

懒汉式 SingletonDemo02.java

较比饿汉式的话效率低,但是可以合理分配空间,更灵活。需要考虑线程安全(可以延时加载)

package 单例模式;
//懒汉式单例
public class SingletonDemo2 {
   //1.私有化构造器
 private SingletonDemo2() {}
   //2.类的初始化的时候不立即加载对象
 private static SingletonDemo2 instance=null;   //先为null节省空间,根据需要再实例
   //提供获取该对象的方法,有synchronized,效率较低
 public static synchronized SingletonDemo2 getInstance() {        //不立即加载的话多个线程排队会有线程安全所以要有锁
  if(instance==null) {
   instance=new SingletonDemo2();
  }
  return instance;
 }
}
class Test2{
 public static void main(String[] args) {
  // TODO 自动生成的方法存根
       SingletonDemo2 instance=SingletonDemo2.getInstance();
       SingletonDemo2 instance2=SingletonDemo2.getInstance();
       System.out.print(instance==instance2); //true,的确是单例
 }
}

DCL懒汉式 SingletonDemo3.java

较懒汉式相比引进了volatile避免指令的重排还有双重检测。synchronized锁的不是方法而是改为同步代码块会使得效率较高一些,但是仍然会有线程安全问题(偶尔有问题不建议使用)

package 单例模式;
//DCL懒汉式单例
public class SingletonDemo3 {
   //1.私有化构造器
 private SingletonDemo3() {}
   //2.类的初始化的时候不立即加载对象
 //volatile:防止极端情况在实例类的时候返回实例加重新实例,作用:能够在返回实例的时候其它实例失效
 private volatile static SingletonDemo3 instance=null;
   //提供获取该对象的方法,有synchronized,效率较低
 public static SingletonDemo3 getInstance() {        //不立即加载的话多个线程排队会有线程安全所以要有锁
  if(instance==null) {
   synchronized(SingletonDemo3.class) {
    if(instance==null) {          //双重检测
       instance=new SingletonDemo3();
    }
   }
  }
  return instance;
 }
 //考虑极端问题:1.分配内存,2.执行构造方法,3.指向地址
}
class Test3{
 public static void main(String[] args) {
  // TODO 自动生成的方法存根
       SingletonDemo3 instance=SingletonDemo3.getInstance();
       SingletonDemo3 instance2=SingletonDemo3.getInstance();
       System.out.print(instance==instance2); //true,的确是单例
 }
}

饿汉改进式 SingletonDemo4.java

综合了前面的优点,可以延时加载而且调用效率高,线程安全
但是最重要的是这个可以利用反射来破坏掉private的字段然后实现多个实例,即使可以不断加判断来限制反射,但是反射也可以不停的去破坏判断的字段

package 单例模式;
//饿汉式单例
public class SingletonDemo4 {
   //1.私有化构造器
 private SingletonDemo4() {}
   //2.静态内部类  只有在调用内部类才会加载实例,避免了饿汉开始加载
 private static class InnerClass{
  private static final SingletonDemo4 instance=new SingletonDemo4();
 }
   //提供获取该对象的方法,线程安全
 public static SingletonDemo4 getInstance() {
  return InnerClass.instance;
 }
}
class Test4{
 public static void main(String[] args) {
  // TODO 自动生成的方法存根
       SingletonDemo4 instance=SingletonDemo4.getInstance();
       SingletonDemo4 instance2=SingletonDemo4.getInstance();
       System.out.print(instance==instance2); //true,的确是单例
 }
}

枚举单例 SingletonDemo5.java (推荐使用)

不能延时加载但是调用效率高,线程安全与饿汉式优缺点一样
底层原码有防止反射破坏枚举单例的代码

package 单例模式;
//枚举单例  安全效率高不能延时加载,但是底层原码有防止反射破坏枚举单例
public enum SingletonDemo5 {
    INSTANCE; 
 public SingletonDemo5 getInstance() {
  return INSTANCE;
 }
}
class Test5{
 public static void main(String[] args) {
  // TODO 自动生成的方法存根
  SingletonDemo5 instance=SingletonDemo5.INSTANCE;
  SingletonDemo5 instance2=SingletonDemo5.INSTANCE;
       System.out.print(instance==instance2); //true,的确是单例
 } 
}

学单例模式的初衷:

  1. 全局可以访问,优先共享资源访问,因为只有一个实例去调用
  2. 只要是合格的开发者都基本要掌握,众多原码都含有单例模式
  3. 通过5种单例模式能学会考虑线程安全等多方面发散思维
  4. 数据库可以以单例模式加数据连接池进行访问,为了了解单例对于数据库的访问有何好处?这里可在评论讨论讨论
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值