1、前言单例模式,属于建立类型的一种经常使用的软件设计模式。经过单例模式的方法建立的类在当前进程中只有一个实例(根据须要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例)--来自百度百科数据库
单例模式可让咱们只建立一个对象从而避免了频繁建立对象致使的内存消耗和垃圾回收。设计模式
单例模式只容许建立一个对象,所以节省内存,加快对象访问速度,所以对象须要被公用的场合适合使用,如多个模块使用同一个数据源链接对象等等。如:安全
项目中的具体应用:多线程
单例模式有八种方式:ide
代码实现:工具
/** * 单例模式 * @Author: crush * @Date: 2021-08-06 9:14 * version 1.0 */ public class SingletonTest1 { public static void main(String[] args) { // 获取两次,看获取到的对象 确实是单例的吗 Singleton singleton = Singleton.getInstance(); Singleton singleton1 = Singleton.getInstance(); System.out.println(singleton == singleton1); System.out.println("singleton hashcode:"+singleton.hashCode()); System.out.println("singleton1 hashcode:"+singleton1.hashCode()); /** * 输出: * true * singleton hashcode:24324022 * singleton1 hashcode:24324022 */ } } /** * 一、饿汉式(静态常量)代码实现 */ class Singleton{ /*** 构造器私有化*/ private Singleton(){}; /** * 在类的内部建立一个对象实例 随当前类加载而加载 没有线程安全问题。 */ private final static Singleton INSTANCE=new Singleton(); /*** 再提供一个 公有的方法来返回这个静态常量*/ public static Singleton getInstance(){ return INSTANCE; } }
结论及优缺:测试
优势:饿汉式(静态常量方式)它不用担忧线程安全问题,它自己就是在类的装载的时候完成实例化的。spa
缺点:可是缺点也在这个地方,无论用不用,只要类装载了,那么他就会直接完成实例化,不能达到懒加载的效果,若是你从始至终都没有使用过这个类,那么就会形成内存的浪费。线程
注意
:你可能会想类都已经加载了,为何我还会不用到呢?设计
在单例模式中大都调用getInstance方法,getInstance这个静态方法可让类加载,那么一样的道理,若是这个类中还有其余的静态方法,你调用它的时候,一样会使类进行装载。
小结:这种单例方式,其实仍是能够用的,至少不用担忧线程同步问题,那种使用特别频繁的类用这种方式仍是没啥问题的,除了可能会致使内存浪费,
/** * 单例模式 2 * * @Author: crush * @Date: 2021-08-06 9:14 * version 1.0 */ public class SingletonTest1 { public static void main(String[] args) { // 咱们去拿两次,看获取到的对象 确实是单例的吗 Singleton singleton = Singleton.getInstance(); Singleton singleton1 = Singleton.getInstance(); System.out.println(singleton == singleton1); System.out.println("singleton hashcode:" + singleton.hashCode()); System.out.println("singleton1 hashcode:" + singleton1.hashCode()); /** * 输出: * true * singleton hashcode:24324022 * singleton1 hashcode:24324022 */ } } /** * 一、饿汉式(静态代码块)代码实现 */ class Singleton { /** * 构造器私有化 */ private Singleton() { } /** * 在类的内部建立一个对象实例 随当前类加载而加载 没有线程安全问题。*/ private static Singleton singleton; static { //改成在静态代码块中 建立单例对象 singleton = new Singleton(); } /** * 再提供一个 公有的方法来返回这个静态常量 */ public static Singleton getInstance() { return singleton; } }
结论:这种方式其实和第一种很是相似,只是将类的实例化过程放进静态代码块而已。优缺点同饿汉式(静态常量)。
/** * 单例模式 * * @Author: crush * @Date: 2021-08-06 9:14 * version 1.0 */ public class SingletonTest3 { public static void main(String[] args) { //懒汉式 线程不安全方式,适合单线程使用 //===========单线程下是安全的 ,测试代码和第一种同样=========== // =========模拟多线程下============= Runnable runnable = new Runnable(){ @Override public void run() { Singleton instance = Singleton.getInstance(); System.out.println(instance.hashCode()); } }; Runnable runnable2 = new Runnable(){ @Override public void run() { Singleton instance1 = Singleton.getInstance(); System.out.println(instance1.hashCode()); } }; Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable2); thread1.start(); thread2.start(); /** * 结果并不惟一, * 可能会出现相同,也有可能不一样,多测几回,就能发现是线程不安全的。 * 94433 * 21648409 */ } } /** * 懒汉式 线程不安全方式 */ class Singleton { /*** 构造器私有化*/ private Singleton() {} /*** 在类的内部建立一个对象实例 随当前类加载而加载 没有线程安全问题。*/ private static Singleton singleton; /** * 提供一个公有的方法 * 当使用到这个方法时,才去建立singleton */ public static Singleton getInstance() { if(singleton==null){ // 经过在这里堵赛的方式来模拟多线程 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } singleton= new Singleton(); } return singleton; } }
结论及优缺:
if(singleton==null)
下,但还将来的及执行,第二个线程就紧随而来也进入了if(singleton==null)
下,那么就会建立多个实例。就不是单例模式了。