单例模式

使用懒汉式加载。 最终可以做到 线程安全,延迟加载,效率高的特点。

package oneDay;

/**
 * 保证一个类仅有一个实例,并提供一个访问它的全局访问点
 * 1:构造方法私有化
 * 2:声明一个本类对象
 * 3:给外部提供一个静态方法获取对象实例
 * <p>
 * <p>
 * 单例设计模式的存在是为了什么?
 * 1:在设计一些工具类的时候,不需要属性这些东西,只需要方法就可以,所以就不掺和对象,只用单例就可以.
 * 2:工具类可能会被频繁调用.
 * 目的是为了节省重复创建对象所带来的内存消耗.从而提高效率.
 * <p>
 * 能不能使用构造方法私有化再加上static 来替代单例?   不能, 构造方法 不能静态化.
 * <p>
 * <p>
 * 在类被加载的时候 因为类中的实例是有 static修饰的,所以当时的实例已经创建好了.
 * 然后继续getIntance的时候  得到的就是 同一个对象.
 */
public class singleCase {
    public static void main(String[] args) {

    }
}


// 饿汉式 : 在类被加载后,对象被创建,到程序结束之后释放.
class Singleton1 {
    private Singleton1() {
    }

    private static Singleton1 s = new Singleton1();

    public static Singleton1 getInstance() {
        return s;
    }

    public void print() {
        System.out.println("测试方法1!");
    }
}
// 懒汉式  : 在第一次调用getInstance方法时,对象被创建,到程序结束后释放.
// 在多线程访问的时候 可能会因为生命周期的问题  而出现程序崩溃错误.
// 可能出现 第一个线程进入 getInstance的时候, 发现s为空 , 在没有 声明实例的时候, 第二个进程也发现了 s 为空.  这个时候   实例就变了.
// 解决方法:
// 1: 将getInstance加上线程锁, 但是这样的话就是 串行执行了 . 效率的良心大大滴坏了.
// 2: 还有一种说话 是给 s = new Singleton2(); 加上同步代码块, 但是这样显然没法解决  实例变化的问题. 是个扯淡的方法.

class Singleton2 {
    private Singleton2() {
    }

    private static Singleton2 s;

    public static Singleton2 getInstance() {
        if (s == null)
            s = new Singleton2();
        return s;
    }

    public void print() {
        System.out.println("测试方法2!");
    }
}

// 3: 结合第二种方法, 实现第三种方法 . 加上同步代码块减少锁影响的颗粒大小, 并且避免第二种方法的问题.  就是在同步代码块中  再次判断是否为空.
//  双重加锁法.  但是这样还可能会存在问题.  因为牵扯到 JVM实现 s = new Singleton3(); 的指令顺序问题 .
//  其指令大致分为以下三步:   1 申请一块内存空间用于存放实例内容 2 在该空间实例化对象  3  将该内存地址富裕s
//  底层执行的时候  不一定是按照123 执行的,  有可能是132 (底层代码速度优化方案.). 这样的话 在没有实例化对象的时候 , s不为null , 这样另一个线程发现s 不为空, 但是拿到的是空的s , 这个时候程序就炸了.
class Singleton3 {
    private Singleton3() {
    }

    private static Singleton3 s;

    public static Singleton3 getInstance() {
        if (s == null)
            synchronized (Singleton3.class) {
				/* 第三种方案对  对二种方法的改进 */
                if (s == null) {
                    s = new Singleton3();
                }
            }
        return s;
    }

    public void print() {
        System.out.println("测试方法2!");
    }
}
// 4: 为了解决第三种方案的缺陷,  我们需要禁止代码重排. 由此而生第四种方案, 这个应该是最完美的方案了.
class Singleton4 {
	private Singleton4() {
	}

	/* 第四种方案对第三种的优化 */
	private static volatile Singleton4 s;

	public static Singleton4 getInstance() {
		if (s == null)
			synchronized (Singleton4.class) {
				/* 第三种方案对  对二种方法的改进 */
				if (s == null) {
					s = new Singleton4();
				}
			}
		return s;
	}

	public void print() {
		System.out.println("测试方法2!");
	}
}

使用饿汉式配合类装载机制,也可以实现懒加载和线程安全,以及高效。

public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

类加载器加载类的时候,会将静态属性直接初始化。 通过这里类加载器的特性, 我们可以做到线程安全。 通过内部类的方式,实现懒加载。

原文地址:https://www.cnblogs.com/A-FM/p/10543245.html