1.单例模式

在这里插入图片描述
在这里插入图片描述

  • 饿汉单例模式和懒汉单例模式构造方法都是私有的,因而是不能被继承的

1.懒汉式

双重检验实现
  • 是否 Lazy 初始化:是

  • 是否多线程安全:是

  • 描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。getInstance() 的性能对应用程序很关键。

1.为什么使用volitale关键字?
  • 禁止指令重排。
    因为singleton = new Singleton()这句话分为3步:
    • 1.为singleton分配内存空间;
    • 2.初始化singleton;
    • 3.将singleton指向分配的空间。

单线程下不会出问题。多线程下,如果指令重排,顺序变为1-3-2.会出现如下情况

2.为什么2次校验singleton?
  • 第1次校验是为了效率。因为单例模式只需要1次创建实例,所以当创建1个实例之后,再次调用getInstance()方法,就不会进入synchronized同步代码块,不用再竞争锁。直接返回实例即可。
  • 第2次校验是为了防止二次创建实例。假设:线程t1由于第1次判断为真,准备继续执行,t2线程却抢占了资源,也通过了第1次校验,进入了同步代码块,也通过了第2次校验,然后调用了getInstance()方法,创建了实例。等t2线程完成任务,t1会继续向下执行,再创建1个实例。所以会导致创建多个实例的情况发生。加上第2次校验,就可以完全避免此问题。
public class Singleton {
    1.volatile关键字,禁止指令重排
    private static volatile Singleton singleton = null;
    2.只能内部调用,所以不是public
    2.构造方法私有,所以不能被继承
    private Singleton(){
    }
    
    public static Singleton getInstance(){
        1.第一次校验singleton是否为空
        if (singleton==null){
            synchronized (Singleton.class){
                2.第2次校验singleton是否为空
                if (singleton==null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

2.饿汉式

  • 是否多线程安全:是
  • 描述:这种方式比较常用,但容易产生垃圾对象。
    • 优点:没有加锁,执行效率会提高。
    • 缺点:类加载时就初始化,浪费内存。

它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。

public class Singleton {  
	1.静态方法加载
    private static Singleton instance = new Singleton();  
    2.构造方法私有,所以不能被继承
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

2.工厂模式

  • 优点:

    • 1、一个调用者想创建一个对象,只要知道其名称就可以了。
    • 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
    • 3、屏蔽产品的具体实现,调用者只关心产品的接口。
  • 缺点:

    • 1.每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
  • 实现:
    创建一个 Phone 接口和实现 Phone 接口的实体类。下一步是定义工厂类 ShapeFactory。这样主程序的调用只涉及shapeFactory而创建对象的接口,让其子类自己决定实例化哪一种产品,工厂模式使其创建过程延迟到子类进行。

1.创建产品的接口、抽象类
abstract class Product {
    public abstract String getProductName();
}

2.实现接口
class Telephone extends Product{
    @Override
    public String getProductName() {
        return "TelePhone";
    }
}
2.2再次实现接口
class Personalcomputer extends Product{
    @Override
    public String getProductName() {
        return "Personalcomputer";
    }
}
3.创建工厂类
class Facotry {

    public static final String 	TELEPHONE = "telephone";
    public static final String 	PersonalCom = "Personalcomputer";
    1.静态方法可以直接调用,不必再new对象
    public static Product produceProduct(String tagName){
        Product product = null;
        if(tagName.equals(TELEPHONE)){
            product = new Telephone();
        }else if (tagName.equals(PersonalCom)){
            product = new Personalcomputer();
        }
        else{
            return null;
        }
        return product;
    }
}

4.测试工厂类
public class Test {
    public static void main(String[] args) {
        Product product1 = null;
        Product product2 = null;
        1.按名称,获得对象
        product1 = Facotry.produceProduct(Facotry.TELEPHONE);
        product2 = Facotry.produceProduct("Personalcomputer");
        
        System.out.println("产品1名称:"+product1.getProductName());
        System.out.println("产品2名称:"+product2.getProductName());
    }
}

更多推荐