设计模式-单例模式

1、单例模式的简介

定义:属于创建型模式,一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象

目标:保证一个类仅有一个实例,并提供一个访问它的全局访问点

解决问题:一个类被频繁的创建和销毁

说明:单例类只能有一个实例,必须自己创建自己的唯一实例,必须给所有其他对象提供这一实例

2、懒汉式,线程不安全

定义:最基本最简单的单例模式实现方式,使用实例的时候才会去初始化

优点:简单

缺点:线程不安全,不适合多线程

实现:

//单例类
public class lazyA {
    private static lazyA lazya;
    /**
     * 为了规范,添加空白的构造函数
     */
    public lazyA(){

    }
    public static lazyA getName (){
        if(lazya == null){
            lazya = new lazyA();
            System.out.println("This is a new lazyA");
        }else{
            System.out.println("This is exist a lazyA");
        }
        return lazya;
    }
    public void show(){
        System.out.println("How are you");
    }
}

//测试方法
 public static void main(String[] args) {
        lazyA lazyA1 = design.single.lazyA.getName();
        lazyA1.show();
        System.out.println("========================");
        lazyA lazyA2 = design.single.lazyA.getName();
        lazyA2.show();
        System.out.println("========================");
        System.out.println(lazyA1==lazyA2);
    }
//测试结果
This is a new lazyA
How are you
========================
This is exist a lazyA
How are you
========================
true

3、懒汉式,线程安全

定义:最基本最简单的单例模式实现方式,使用实例的时候才会去初始化,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步

优点:第一次调用才初始化,避免内存浪费

缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率

实现:

//单例类
public class lazyB {
    private static lazyB lazya;
    /**
     * 为了规范,添加空白的构造函数
     */
    public lazyB(){

    }
    public static synchronized lazyB getName (){
        if(lazya == null){
            lazya = new lazyB();
            System.out.println("This is a new lazyB");
        }else{
            System.out.println("This is exist a lazyB");
        }
        return lazya;
    }
    public void show(){
        System.out.println("How are you");
    }
}

//测试方法
 public static void main(String[] args) {
        lazyB lazyB1 = design.single.lazyB.getName();
        lazyB1.show();
        System.out.println("========================");
        lazyB lazyB2 = design.single.lazyB.getName();
        lazyB2.show();
        System.out.println("========================");
        System.out.println(lazyB1==lazyB2);
    }
//测试结果
This is a new lazyB
How are you
========================
This is exist a lazyB
How are you
========================
true

4、饿汉式

定义:这种方式比较常用,但容易产生垃圾对象,类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了

优点:线程安全,没有锁,效率高

缺点:类加载时就初始化,浪费内存

实现:

//单例类
public class hungry {
    public static hungry hungry = new hungry();
    private hungry(){
        System.out.println("very hungry");
    }
    public static hungry getHungry(){
        System.out.println("me too");
        return hungry;
    }
    public void show(){
        System.out.println("hungry show");
    }
}

//测试方法
 public static void main(String[] args) {
        hungry hungry1 = design.single.hungry.getHungry();
        hungry1.show();
        System.out.println("===============================");
        hungry hungry2 = design.single.hungry.getHungry();
        hungry2.show();
        System.out.println("========================");
        System.out.println(hungry1==hungry2);
    }
//测试结果
very hungry
me too
hungry show
===============================
me too
hungry show
========================
true

5、枚举

定义:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法 它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化

优点:简单,容易实现,支持多线程

缺点:JDK1.5后加入的enum特性,不能通过 reflection attack 来调用私有构造方法

实现:

//单例类
public class enumTest {
    private enumTest() {

    }

    static enum singleEnum {
        //创建一个枚举对象,该对象为单例
        SINGLE_ENUM;
        private  enumTest enumTest;

        private singleEnum() {
            System.out.println("this is a enum");
            enumTest = new enumTest();
        }
        public enumTest getEnumTest(){
            System.out.println("get enumEnum");
            return enumTest;
        }
    }
    public  static enumTest getInstance(){
        System.out.println("this is a enumTest");
        return singleEnum.SINGLE_ENUM.getEnumTest();
    }
}

//测试方法
 public static void main(String[] args) {
       enumTest enumTest1 = enumTest.getInstance();
        System.out.println("========================");
        enumTest enumTest2 = enumTest.getInstance();
        System.out.println("========================");
        System.out.println(enumTest1==enumTest2);
    }
//测试结果
this is a enumTest
this is a enum
get enumEnum
========================
this is a enumTest
get enumEnum
========================
true

6、双检锁(DCL)

定义:这种方式采用双锁机制,安全且在多线程情况下能保持高性能

优点:性能高

缺点:实现复杂

实现:

//单例类
public class Dcl {
    private static volatile Dcl dcl = null;
    private Dcl(){

    }
    public static Dcl getDcl(){
        System.out.println(dcl);
        System.out.println("one:"+(dcl == null));
        if(dcl == null){
            synchronized (Dcl.class) {
                if (dcl == null) {
                    dcl = new Dcl();
                }
                System.out.println("two:"+(dcl == null));
            }
        }
        return dcl;
    }
}

//测试方法
public  class Test {
    public static void main(String[] args) {
        Dcl dcl1 = Dcl.getDcl();
        System.out.println("===============================");
        Dcl dcl2 = Dcl.getDcl();
        System.out.println("========================");
        System.out.println(dcl1==dcl2);
    }
}
//测试结果
null
one:true
two:false
===============================
design.single.Dcl@4554617c
one:false
========================
true

7、静态内部类

定义:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用

实现:

//单例类

public class StaticTest {
    private static final StaticTest STATIC_TEST = new StaticTest();
    private StaticTest(){
        System.out.println("one StaticTest");
    }
    public static  final  StaticTest getStaticTest(){
        System.out.println("two StaticTest");
        return StaticTest.STATIC_TEST;
    }
}

//测试方法
 public static void main(String[] args) {
        StaticTest staticTest1 = StaticTest.getStaticTest();
        System.out.println("==============================");
        StaticTest staticTest2 = StaticTest.getStaticTest();
        System.out.println("==============================");
        System.out.println(staticTest1==staticTest2);

    }
//测试结果
one StaticTest
two StaticTest
==============================
two StaticTest
==============================
true
posted @ 2020-09-29 11:40  CarBlack  阅读(120)  评论(0编辑  收藏  举报