创建者模式-单例模式
创建者模式主要关注点:怎样创建对象
特点:将创建对象与使用分离
创建者模式分为:
- 单例模式
- 工厂方法模式
- 抽象工程模式
- 原型模式
- 建造者模式
单例设计模式
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。
单例模式结构
单例模式主要有以下角色:
- 单例类。只能创建一个实例类
- 访问类。使用单例类
单例模式实现
单例设计模式分类两种:
- 饿汉式:类加载就会导致该单实例对象被创建
- 饿汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建
饿汉式-方式1(静态变量方式)
package com.ryan.pattern.singleton.demo1;
/*
饿汉式:静态成员变量
*/
public class Singleton {
//1.私有构造方法(不让外界访问)
private Singleton(){}
//2.在本类中创建本类对象(3中静态方法不能直接访问非静态对象,所以加上static修饰,改成静态)
private static Singleton instance = new Singleton();
//3.提供一个公共的访问方式,让外界获取该对象
public static Singleton getInstance(){
return instance;
}
}
测试类:
package com.ryan.pattern.singleton.demo1;
public class Client {
public static void main(String[] args) {
//创建Singleton类的对象
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
//判断获取到的两个对象是否是同一个对象
System.out.println(instance == instance1);//同一个地址,同一个对象
}
}
饿汉式-方式2(静态代码块方式)
饿汉式说明:
该方式在成员位置声明Singleton类型的静态变量,而对象的创建是在静态代码块中,也是对着类的加载而创建。所以饿汉式存在内存浪费问题。
package com.ryan.pattern.singleton.demo2;
/*
饿汉式:静态代码块
*/
public class Singleton {
//私有构造方法
private Singleton(){};
//声明Singleton类型的变量
private static Singleton instance;//null
//在静态代码块中赋值
static {
instance = new Singleton();
}
//对外提供获取该类对象的方法
public static Singleton getInstance(){
return instance;
}
}
测试类:
package com.ryan.pattern.singleton.demo2;
public class Client {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
//判断两次获取到的Singleton对象是否是同一个对象
System.out.println(instance == instance1);
}
}
懒汉式1-线程不安全
package com.ryan.pattern.singleton.demo3;
/*
懒汉式:线程不安全
*/
public class Singleton {
//私有构造方法
private Singleton(){};
//声明Singleton类型的变量instance
private static Singleton instance;//只是声明一个该类型的变量,并没有进行赋值
//对外提供访问方式
public static Singleton getInstance(){
//instance = new Singleton();错误,每次调用都会创建对象
//判断instance是否为null,如果为null,说明还没有创建Singleton类的对象
//如果没有,创建一个并返回,如果有,直接返回
if (instance == null){
//线程1等待,线程2获取到cpu的执行权,也会进入到该判断里面
instance = new Singleton();
}
return instance;
}
}
懒汉式-线程安全
package com.ryan.pattern.singleton.demo3;
/*
懒汉式:线程安全
方法增加synchronized
*/
public class Singleton {
//私有构造方法
private Singleton(){};
//声明Singleton类型的变量instance
private static Singleton instance;//只是声明一个该类型的变量,并没有进行赋值
//对外提供访问方式
public static synchronized Singleton getInstance(){
//instance = new Singleton();错误,每次调用都会创建对象
//判断instance是否为null,如果为null,说明还没有创建Singleton类的对象
//如果没有,创建一个并返回,如果有,直接返回
if (instance == null){
//线程1等待,线程2获取到cpu的执行权,也会进入到该判断里面
instance = new Singleton();
}
return instance;
}
}
懒汉式-双重检查锁
懒汉模式中的加锁问题,对于getInstance()方法来说,绝大部分的操作都是读操作,读操作是线程安全的,所以没必要让每个线程必须持有锁才能调用该方法,需要调整加锁时机。由此也产生了一种新的实现模式:双重检查锁模式
双重检查锁模式是一种非常好的单例模式,解决了单例、性能、线程安全问题,下面的双重检查锁模式可能存在问题,多线程的情况下,可能会出现空指针问题,出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。
要解决双重检查锁模式带来的空指针异常的问题,只需要使用volatile关键字,volatile关键字可以保证可见性和有序性。
package com.ryan.pattern.singleton.demo4;
/*
双重检查锁
*/
public class Singleton {
//私有构造方法
private Singleton(){};
//声明Singleton类型的变量
private static Singleton instance;
//对外提供访问方式
public static Singleton getInstance(){
//第一次判断,如果instance的值不为null,不需要抢占锁,直接返回对象
if(instance == null){
synchronized (Singleton.class){
//第二次判断
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
增加volatile改进:
package com.ryan.pattern.singleton.demo4;
/*
双重检查锁
*/
public class Singleton {
//私有构造方法
private Singleton(){};
//声明Singleton类型的变量
private static volatile Singleton instance;//保证指令有序,解决多线程空指针问题
//对外提供访问方式
public static Singleton getInstance(){
//第一次判断,如果instance的值不为null,不需要抢占锁,直接返回对象
if(instance == null){
synchronized (Singleton.class){
//第二次判断
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}