zoukankan      html  css  js  c++  java
  • 单例模式

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

    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;
        }
    }
    

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

  • 相关阅读:
    tomcat容器启动的启动过程(三)
    tomcat源码分析(二)启动过程
    tomcat源码分析(一)
    spring 整合redis
    redis win版安装
    java虚拟机存储区
    java代码块 静态、非静态
    Vulkan Tutorial 08 交换链
    Vulkan Tutorial 07 Window surface
    Vulkan Tutorial 06 逻辑设备与队列
  • 原文地址:https://www.cnblogs.com/A-FM/p/10543245.html
Copyright © 2011-2022 走看看