Java设计模式-单例模式(考虑并发和线程安全的)

单例模式,参考完整代码在GitHub

地址:https://github.com/zhang-xiaoxiang/patter23 

或者https://github.com/zhang-xiaoxiang/DesignPatterns23

一般三步走,1初始化2构造器私有3提供获取实例的方法

1 单例模式---饿汉式

package com.demo.singleton;

/**
 * SingletonDemo1:单例模式---饿汉式
 *
 * 优点:线程安全
 * 缺点:没有延迟加载的优势(即容易造成不分青红皂白new了个可能暂时无用的单例对象从而造成资源浪费)
 *
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */
public class SingletonDemo1 {

    /**
     * 1 类初始化(既然是饿汉那么上来就new了再说呗)
     * 这里说明一下为什么声明成static,1是语法要求Non-static field 'instance' cannot be referenced from a static context,
     * 为了给外部提供一个不是new出实例的方法,采用的是提供一个静态方法getInstance(),静态方法调动的必须是静态的变量;2是让外部不能以任何方式引用this 或super
     * 总之就是被迫的使用static,记住就行了哈
     */
    private static SingletonDemo1 instance = new SingletonDemo1();

    /**
     * 2 私有构造器
     * 这里说明一下private(在本类的如果要继续new对象可以,private,public修饰构造器没有区别,类的内部操作属性和方法统统具有可见性,
     * 但是外部调用该类,必须使用private修饰以防止外部new出新对象,所以这里必须是private修饰构造器,后面设计到的单例模式的其他方式都是这个操作,不在后文叙述)
     */
    private SingletonDemo1() {
    }

    /**
     * 3:提供获取单实例方法,方法没有同步(加锁),调用效率高!
     * 说明一下,既然不让外部new对象,但是至少得给个方式让外部产生一个单实例吧,那么这里"被迫"使用静态方法,而且这也是最科学的
     */
    public static SingletonDemo1 getInstance() {
        return instance;
    }

    //强烈提示:不要在本类使用main方法测试,因为本类private是控制不了为私有,所以在其他类测试哈
}

/**
 * test01:测试类,为了方便观察测试,直接写在这里测试(也可以单独在外部写个测试类)
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */
class Test01 {
    public static void main(String[] args) {
        SingletonDemo1 instance = SingletonDemo1.getInstance();
        SingletonDemo1 instance2 = SingletonDemo1.getInstance();
        System.out.println(instance);
        System.out.println(instance2);
        //true
        System.out.println(instance == instance2);

    }
}

2 单例模式---懒汉式 不推荐

package com.demo.singleton;

/**
 * SingletonDemo2:单例模式---懒汉式
 * 优点:延迟加载(资源利用合理,用的时候才new)
 * 缺点:synchronized加了线程安全效率低,不加线程不安全效率高
 *
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */
public class SingletonDemo2 {

    /**
     * 1:类初始化(既然是懒汉式,那就懒得不急着new对象)
     */
    private static SingletonDemo2 instance;

    /**
     * 2:私有化构造器
     */
    private SingletonDemo2() {
    }

    /**
     * 3:提供获取单实例方法(静态工厂方法)
     * 这里加synchronized和不加是对线程安全的考虑,不加线程不安全,调用效率高一些,反之线程安全效率低
     * 这个地方可以优化,可以产生衍生版本,这个是屌丝版本哈
     */
    public static synchronized SingletonDemo2 getInstance() {
        //如果方法不加锁,多个线程(并发环境下)同时访问到这段代码的时候会出现"判断失误",所以这里加了锁保证线程安全
        if (instance == null) {
            instance = new SingletonDemo2();
        }
        return instance;
    }

}

/**
 * Test02:单例模式---懒汉式
 *
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */

class Test02 {
    public static void main(String[] args) {
        SingletonDemo2 instance = SingletonDemo2.getInstance();
        SingletonDemo2 instance2 = SingletonDemo2.getInstance();
        System.out.println(instance);
        System.out.println(instance2);
        //true
        System.out.println(instance == instance2);

    }

}
3单例模式---双重同步锁(懒汉模式衍生版本)
package com.demo.singleton;

/**
 * SingletonDemo3:单例模式---双重同步锁(懒汉模式衍生版本)
 *
 * 优点:线程安全(因为加了volatile)
 *
 * volatile作用:解决并发问题,以下会涉及到Java内存模型的知识
 * 主要应用1:修饰线程的标志,2:就是单例模式的双重检测机制
 *
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */
public class SingletonDemo3 {
    /**
     * 1:初始化对象   使用volatile解决并发问题 单例对象 volatile + 双重检测机制 -> 禁止指令重排
     */
    private volatile static SingletonDemo3 instance = null;

    /**
     * 2:构造器私有化
     */
    private SingletonDemo3() {
    }

    /**
     * 3:提供获取单实例方法(就是个静态工厂方法哈)
     *
     * @return
     */
    public static SingletonDemo3 getInstance() {
        //这里前面如果不加volatile,那么后面的双重判断将会出现"误判",导致线程不安全,所以加了保证安全
        //第一重检查锁定
        if (instance == null) {
            synchronized (SingletonDemo3.class) {
                //第二重检查锁定
                if (instance == null) {
                    synchronized (SingletonDemo3.class) {
                        //注意:非原子操作
                        instance = new SingletonDemo3();
                    }
                }
            }
        }
        return instance;
    }
}

/**
 * Test03:双重检查锁测试
 *
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */
class Test03 {
    public static void main(String[] args) {
        SingletonDemo3 instance = SingletonDemo3.getInstance();
        SingletonDemo3 instance2 = SingletonDemo3.getInstance();
        System.out.println(instance);
        System.out.println(instance2);
        //true
        System.out.println(instance == instance2);
    }
}

4单例模式---静态内部类(饿汉模式衍生版本)推荐使用

package com.demo.singleton;
/**
 * SingletonDemo4:单例模式---静态内部类(饿汉模式衍生版本)
 *
 * (推荐使用)
 * 优点:线程安全,并且实现了延时加载(调用效率高)!
 *
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */
public class SingletonDemo4 {
	/**
	 * 1:初始化对象(使用的静态内部类方式)
	 */
	private static class SingletonClassInstance {
		private static final SingletonDemo4 INSTANCE = new SingletonDemo4();
	}

	/**
	 * 2:构造器私有化
	 */
	private SingletonDemo4(){
	}

	/**
	 * 3提供获取实例的方法,该方法没有同步,调用效率高!
	 * @return
	 */
	public static SingletonDemo4  getInstance(){
		return SingletonClassInstance.INSTANCE;
	}
}

/**
 * Test04:静态内部类实现单例模式测试
 *
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */
class Test04 {
	public static void main(String[] args) {
		SingletonDemo4 instance = SingletonDemo4.getInstance();
		SingletonDemo4 instance2 = SingletonDemo4.getInstance();
		System.out.println(instance);
		System.out.println(instance2);
		//true
		System.out.println(instance == instance2);
	}
}

5单例模式---枚举实现

package com.demo.singleton;

/**
 * SingletonDemo5:单例模式---枚举实现
 *
 * 优点:这个是线程最安全,抗并发能力最强的
 * 缺点:没有延时加载
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */
public enum SingletonDemo5 {

	/**
	 * 这个枚举元素,本身就是单例对象!天然单例
	 */
	INSTANCE;

	/**
	 * 添加自己需要的操作!
	 */
	public void singletonOperation(){
		System.out.println("枚举是天生的单例!");
	}
}

/**
 * Test05:枚举式实现单例模式测试
 *
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */
class Test05 {
	public static void main(String[] args) {
		SingletonDemo5 instance=SingletonDemo5.INSTANCE;
		SingletonDemo5 instance2=SingletonDemo5.INSTANCE;
		System.out.println(instance);
		System.out.println(instance2);
		//true
		System.out.println(instance==instance2);
	}
}

6单例模式---枚举模式2 推荐使用

package com.demo.singleton;


/**
 * SingletonDemo6:单例模式---枚举模式2
 *
 * 推荐使用
 * 优点:线程最安全
 *
 * @author zhangxiaoxiang
 * @date 2019/8/12
 */

public class SingletonDemo6 {
    /**
     * 1:初始化
     */
    private enum Singleton {
        /**
         * 枚举实例
         */
        INSTANCE;

        private SingletonDemo6 singleton;

        /**
         * JVM保证这个方法绝对只调用一次
         */
        Singleton() {
            singleton = new SingletonDemo6();
        }

        public SingletonDemo6 getInstance() {
            return singleton;
        }
    }

    /**
     * 2:私有构造函数
     */
    private SingletonDemo6() {
    }

    /**
     * 3:提供一个获取单实例的方法
     *
     * @return
     */
    public static SingletonDemo6 getInstance() {
        return Singleton.INSTANCE.getInstance();
    }

}

/**
 * Test06:枚举单例测试2
 *
 * @author zhangxiaoxiang
 * @date 2019/8/12
 */

class Test06 {
    public static void main(String[] args) {
        SingletonDemo6 instance = SingletonDemo6.getInstance();
        SingletonDemo6 instance2 = SingletonDemo6.getInstance();
        System.out.println(instance);
        System.out.println(instance2);
        //true
        System.out.println(instance == instance2);
    }
}

7单例模式---防止反射和反序列化漏(懒汉式衍生版本2) 

package com.demo.singleton;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * SingletonDemo7:单例模式---防止反射和反序列化漏(懒汉式衍生版本2)
 *
 * 优点:线程安全且带有延迟
 * 缺点:调用效率低
 *
 * @author zhangxiaoxiang
 * @date 2019/8/9
 */

public class SingletonDemo7 implements Serializable {
	/**
	 * 1:类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
	 */
	private static SingletonDemo7 instance;

	/**
	 * 2:私有化构造器
	 */
	private SingletonDemo7(){
		if(instance!=null){
			throw new RuntimeException();
		}
	}

	/**
	 * 3:提供一个单实例方法,方法同步,调用效率低!
	 * @return
	 */
	public static  synchronized SingletonDemo7 getInstance(){
		if(instance==null){
			instance = new SingletonDemo7();
		}
		return instance;
	}

	/**
	 * 反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象!
	 * @return
	 * @throws ObjectStreamException
	 */
	private Object readResolve() throws ObjectStreamException {
		return instance;
	}

}
/**
 * Test06:防止反射和反序列化漏测试
 *
 * @author zhangxiaoxiang
 * @date 2019/8/12
 */
class Test07{
	public static void main(String[] args) {
		SingletonDemo7 instance = SingletonDemo7.getInstance();
		SingletonDemo7 instance2 = SingletonDemo7.getInstance();
		System.out.println(instance);
		System.out.println(instance2);
		//true
		System.out.println(instance==instance2);
	}
}

 

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页