Java单例模式---饿汉式,懒汉式,双重校验锁

单例模式

一、概述

设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式

二、单例设计模式(Singleton)

采取一定的方法保证在软件系统中对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们让类在虚拟机中只产生一个对象,首先必须将类的构造器私有化(private),这样就不能用new操作符在类的外部产生该类的对象,但在类的内部仍可以产生类的对象。因为在类的外部开始无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以该类内部产生的该类对象的变量必须定义为静态。

三、实现

1、饿汉式

public class SingletonTest {
    public static void main(String[] args) {
        Bank instance1 = Bank.getInstance();
        Bank instance2 = Bank.getInstance();
    }
}

/**
 * 饿汉式
 */
class Bank{
    /**
     * 1、私有化构造器
     */
    private  Bank(){

    }
    /**
     * 2.内部创建类的对象
     */
    private static Bank instance=new Bank();
    /**
     * 3、提供公共的方法,返回类的对象
     */
    public static Bank getInstance(){
        return instance;
    }
}

2、懒汉式

public class SingletonTest2 {
    public static void main(String[] args) {
        Bank instance = Bank.getInstance();
    }
}

/**
 * 懒汉式
 */
class Order{
    /**
     * 1、私有化类的构造器
     */
    private Order(){

    }
    /**
     * 2、声明当前类的对象,没有初始化
     */
    private static Order instance=null;

    /**
     * 3、声明public、static的返回当前类的对象
     * @return
     */
    public static Order getInstance(){
        if(instance==null){
            instance=new Order();
        }
        return instance;
    }
}

3、区别

  • 懒汉式:优点:延迟对象的创建。缺点:线程不安全
  • 饿汉式:优点:线程安全。缺点:对象加载时间过长。

四、双重校验锁

1. volatile关键字

  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
  • 禁止指令重排序

2. 代码演示

public class Sington {
    public static void main(String[] args) {
    }

    private static volatile Sington SINGTON;

    public static Sington getInstance() {
        //使用volatile修饰SINGTON保证可见性,提高效率
        if (SINGTON == null) {//①
            synchronized (Sington.class) {//保证原子性
                //为了保证单例,返回的是同一个对象
                if (SINGTON == null) {
                    //② 分配内存空间
                    //③ 初始化对象
                    //④ 赋值给变量 
                    SINGTON = new Sington();
                }
            }
        }
        return SINGTON;
    }
}
  • 注意:假设SINGTON不加volatile修饰
    • 在new对象的时候指令可分解为代码中的三步
    • 若此时先执行步骤②和④,此时变量SINGTON已经有值,但它不是Sington()的实例
    • 此时步骤①处判断SINGTON!=null,则返回的对象就会出错,因为不是Sington()的对象

五、使用场景

单例模式是生成一个实例,减少系统性能开销,当一个对象产生需要多的资源时,如读取配置。产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留在内存当中。

  • 网站的计数器:一般为单例模式,否则难以同步
  • 应用程序的日志应用:由于共享日志文件一直处于打开状态,只能有一个实例去操作,否则能容不好追加
  • 数据库连接池:数据库连接是一种数据库资源
  • Windows的任务管理器
  • Windows的Recycle Bin(回收站):系统运行过程中回收站一直维护着仅有的一个实例。

你可能感兴趣的:(Java学习)