java常用设计模式(一)单例模式

  第一次写博客,也是第一篇,从单例模式开始,不足之处,望各位看官海涵。

 简介

  首先我们都知道单例模式是java常用的23种设计模式之一,它的用途可谓是非常广泛。它的核心就在于单实例,即整个环境中该类有且只能有一个对象。而java创建实例的方式已知的有四种,分别是通过new、clone、反射或者序列化这四种方式去创建实例,怎样保证单例呢,下面且听我一一道来。

 单例模式的常见写法:

  1.基础饿汉式单例

    优点:

    类加载时就去初始化,没有线程安全问题,不能通过new创建实例

    缺点:

    ①.能通过反射或者序列化去创建新的实例(解决方式在最后)

    ②.类加载时就创建好对象,可能会创建出来用不到的实例对象,这样对内存是种浪费

/**
 * 基础饿汉式单例
 */
public class HungrySingleton {

    private static final HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
}

  2.简单懒汉式

    优点:

    懒汉式和饿汉式不同,它不需要在类加载的时候去创建对象,而是在类实例化的时候才会去创建对象,所以不存在内存空间浪费

    缺点:

    ①.懒汉式是线程不安全的,多个线程同时去实例化该对象有可能会生成多个实例对象,破坏单例

    ②.能通过反射或者序列化去创建新的实例(解决方式在最后)

/**
 * 普通的懒汉式
 */
public class LazySingleton {

    private static LazySingleton lazySingleton;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

  3.懒汉式二(双重校验锁-double check)

    优点:

    解决了简单懒汉式的线程安全问题

    缺点:

    ①.加入synchronized关键字,一定程度上影响性能

    ②.能通过反射或者序列化去创建新的实例(解决方式在最后)

/**
 * 双重校验锁
 */
public class DoubleCheckSingleton {

    private DoubleCheckSingleton doubleCheckSingleton;

    private DoubleCheckSingleton(){}

    public DoubleCheckSingleton getInstance(){
        if(doubleCheckSingleton == null){
            synchronized (DoubleCheckSingleton.class){
                if(doubleCheckSingleton == null){
                    doubleCheckSingleton =  new DoubleCheckSingleton();
                }
            }
        }
        return doubleCheckSingleton;
    }
}

  4.懒汉式三(静态内部类)

   优点:

   没有synchronized关键字,不会影响性能,也没有线程安全问题

   缺点:

   能通过反射或者序列化去创建新的实例(解决方式在最后)

/**
 * 静态内部类
 */
public class StaticInnerClassSingleton implements Serializable {

    private StaticInnerClassSingleton(){}

    public static StaticInnerClassSingleton getInstance(){
        return InnerClass.staticInnerClassSingleton;
    }

    static class InnerClass{
        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }
}

  5.枚举类型单例

    优点:枚举的优点就是没有缺点(我本人没有发现,各位大佬有知道的可以告诉我)

/**
 * 枚举类型单例
 */
public enum EnumSingleton {

    INSTANCE;

    public static EnumSingleton getInstance(){
        return INSTANCE;
    }

}

 反射和序列化破坏单例的解决办法

  反射和序列化是破坏单例的两种常见方式,我们在静态内部类的基础上添加解决方案。

  首先我们为该类实现Serializable接口,重写readResolve方法,这样能够解决序列化破坏单例的问题;其次,我们在原本空的构造方法中添加一段代码,去判断实例是否已经存在,如果存在则抛异常,这样能够解决反射破坏单例的问题

import java.io.Serializable;

/**
 * 静态内部类
 */
public class StaticInnerClassSingleton implements Serializable {

    private StaticInnerClassSingleton(){
        if(InnerClass.staticInnerClassSingleton != null){
            throw new RuntimeException("不允许创建多个实例");
        }
    }

    public static StaticInnerClassSingleton getInstance(){
        return InnerClass.staticInnerClassSingleton;
    }

    static class InnerClass{
        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }

    //保证序列化不回破坏单例
    private Object readResolve(){
        return InnerClass.staticInnerClassSingleton;
    }
}

 总结

  简单懒汉式是我们极不推荐的一种形式,因为会存在线程安全的问题,双重校验锁和基础饿汉式是通过牺牲一定性能或者空间来达到实现单例的目的,如果性能要求不高或者内存空间足够的话,可以酌情使用。我们更加推荐的形式是静态内部类和枚举类型的单例,尤其是枚举类型,不需要通过额外的代码去防止序列化和反射破坏单例,这是jdk开发者在源码层面就做过限制的,相对而言,静态内部类虽然需要自己手动去做校验,但是它简单易懂,很容易让人理解。

原文地址:https://www.cnblogs.com/blue-and-white/p/10987144.html

时间: 2024-10-10 20:28:03

java常用设计模式(一)单例模式的相关文章

iOS.常用设计模式.01.单例模式

使用单例模式的类: UIApplication UIAccelerometer NSUserDefaults NSNotificationCenter NSFileManager NSBundle等 Singleton.h #import <Foundation/Foundation.h> @interface Singleton : NSObject // 始终返回同一个Singleton的指针 + (Singleton *)sharedManager; @property (strong,

java常用设计模式之 工厂模式

工厂模式: 定义 一个用于创建对象的接口,让子类决定实例化哪一个类. 一句话概括: 是一个类的实例化延迟到其子类.     适用于 以下情况: ①:当一个类 ,不知道它所必须创建的对象的类的时候. ②:当一个类,希望由它的子类来指定它所创建的对象的时候. ③:当类将创建对象的职责给多个帮助子类中的一个,并且希望将哪一个帮助子类是代理这一信息局部化的时候. 说明: ① Product :定义工厂方法所创建的对象的接口. ② ConcreteProduct:实现Product 接口. ③ Creat

Java常用的设计模式03:常用设计模式之单例模式

1.java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,但只能有一个Printer

java常用设计模式链接

转自:作者:dreamOwn     https://www.cnblogs.com/wabi87547568/p/5280905.html Java中常用的设计模式 1.单例模式 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 总之,选择单例模式就是为了避免不一致状态,避免政出多头. 推荐链接:http://blog.csdn.net/

【JAVA】设计模式之单例模式

前言 java最常见的设计模式就是单例模式,而单例模式最常见的就是懒汉式和饿汉式,现在就分别看一下 1.懒汉式 懒汉式比较懒,当别人用到时才会初始化实例,而当有多个人同时用到就可能产生多个实例,造成线程安全问题. public class Lazy { private static Lazy lazy; private Lazy{ } public static Lazy getLazy() { if(lazy == null){ lazy = new Lazy(); } return lazy

java常用设计模式-单例模式

java设计模式系列之单例模式 单例模式定义 一个类有且仅有一个实例,并且自行实例化向整个系统提供. 单例模式作用 简单来说,就是在整个程序运行的生命期中,任何一个时刻,单例类的实例都只有一个(当然也可以一个都没有). 如何保证对象的唯一性 思想:(1)不让其他程序创建该类对象: (2)在本类中创建该类对象: (3)创建一个对外提供的方法,可以让其他类进行调用. 步骤:(1)因为创建对象的时候都要初始化构造函数,将该类的构造函数私有化,其他程序就无法再创建该类对象: (2)就是在本类中创建本类对

java常用设计模式--单例模式简单例子

package com.ruanyun; /** * @Auther: maxw * @Date: 2018/11/10 17:29 * @Description: */public class Test4 { public static void main(String args[]){ F99 f99 = F99.getInstance(); F99 f100 = F99.getInstance(); System.out.println(f99==f100); }}//假设 F99战机 只

java常用设计模式

一个程序员对设计模式的理解: "不懂"为什么要把很简单的东西搞得那么复杂. 后来随着软件开发经验的增加才开始明白我所看到的"复杂"恰恰就是设计模式的精髓所在,我所理解的"简单"就是一把钥匙开一把锁的模式, 目的仅仅是着眼于解决现在的问题,而设计模式的"复杂"就在于它是要构造一个"万能钥匙",目的是提出一种对所有锁的开锁方案. 在真正理解设计模式之前我一直在编写"简单"的代码.这个&quo

JAVA常用设计模式整理

设计模式:一个程序员对设计模式的理解:“不懂”为什么要把很简单的东西搞得那么复杂.后来随着软件开发经验的增加才开始明白我所看到的“复杂”恰恰就是设计模式的精髓所在,我所理解的“简单”就是一把钥匙开一把锁的模式,目的仅仅是着眼于解决现在的问题,而设计模式的“复杂”就在于它是要构造一个“万能钥匙”,目的是提出一种对所有锁的开锁方案.在真正理解设计模式之前我一直在编写“简单”的代码.这个“简单”不是功能的简单,而是设计的简单.简单的设计意味着缺少灵活性,代码很钢硬,只在这个项目里有用,拿到其它的项目中