单例模式其实很简单,就是将构造函数私有化,然后通过自定义一个方法来获得类的实例。
单利模式分为饿汉模式、懒汉模式
饿汉模式SingletonHungry
public class SingletonHungry { private SingletonHungry(){ } private static SingletonHungry instance = new SingletonHungry(); public static SingletonHungry getInstance(){ return instance; } }
懒汉模式SingletonFull
public class SingletonFull { private SingletonFull(){ } private static SingletonFull instance; public static SingletonFull getInstance(){ if(instance == null){ instance = new SingletonFull(); } return instance; } }
测试类
public class Test { public static void main(String[] args){ /* //饿汉模式 SingletonHungry s1 = SingletonHungry.getInstance(); SingletonHungry s2 = SingletonHungry.getInstance(); if(s1 == s2){ System.out.println("s1和s2是同一个实例"); }*/ //懒汉模式 SingletonFull s1 = SingletonFull.getInstance(); SingletonFull s2 = SingletonFull.getInstance(); if(s1 == s2){ System.out.println("s1和s2是同一个实例"); } } }
控制台输出:s1和s2是同一个实例
饿汉模式与懒汉模式的区别
饿汉模式:在类加载的时候就新建了实例,所以类加载速度比较慢,但程序运行速度比较快,因为是静态的初始实例,所以是线程安全的。
懒汉模式:在需要的时候再新建实例,所以类加载速度比较快,但程序运行速度比较慢(也只是第一次获取实例时)。由于类加载的是并没有new 实例,所以当多线程的时候,可能同时new 多个实例,所以是线程不安全的。
懒汉模式如何实现线程安全?
有三种方法
第一种方法是给获取实例的方法加上同步锁
public class SingletonFull { private SingletonFull(){ } private static SingletonFull instance; public static synchronized SingletonFull getInstance(){ if(instance == null){ instance = new SingletonFull(); } return instance; } }
第二种方法是给new 实例加上同步锁
public class SingletonFull { private SingletonFull(){ } private static SingletonFull instance; public static SingletonFull getInstance(){ synchronized(SingletonFull.class){ if(instance == null){ instance = new SingletonFull(); } } return instance; } }
第三种方法是双重校验锁,结合第一种和第二种方法
public class SingletonFull { private SingletonFull(){ } private static SingletonFull instance; public static synchronized SingletonFull getInstance(){ synchronized(SingletonFull.class){ if(instance == null){ instance = new SingletonFull(); } } return instance; } }