温故而知新 设计模式01 单例模式

01单例模式

用啥方式解决实际问题更合适就用啥方式,我们不追求那些不必要的完美
饿汉模式01 最简单版但是好用
package xzc._01singleton;

/*

  • 饿汉模式01

  • Class.forName() 也行啊

  • 1.放单例的静态变量

  • 2.构造方法私有化

  • 3.取出单例的静态化方法

    • 类加载到内存后就会自动实例化一个单例
  • */
    public class _01hungry {

    public static final _01hungry INSTANCE = new _01hungry();
    private _01hungry() {};
    public static _01hungry getInstance(){
    return INSTANCE;
    }

    public void sayHello(){
    System.out.println(“01hungry”);
    }

    public static void main(String[] args) {
    // _01hungry hungry01 = new _01hungry();
    // _01hungry hungry02 = new _01hungry();
    _01hungry hungry01 = _01hungry.getInstance();
    _01hungry hungry02 = _01hungry.getInstance();
    System.out.println(hungry01==hungry02);
    }
    }

饿汉模式02 静态代码块

package xzc._01singleton;

/*

  • 饿汉模式02 静态代码块

  • Class.forName() 也行啊 暂时放弃

  • 1.放单例的静态变量

  • 2.构造方法私有化

  • 3.取出单例的静态化方法

    • 类加载到内存后就会自动实例化一个单例
  • 不管用到与否 类加载就实例化了

  • */
    public class _02hungry {

    private static final _02hungry INSTANCE;
    /*

    • 执行顺序:
      1、类内容(静态变量、静态初始化块) => 实例内容(变量、初始化块、构造器)
      2、父类的(静态变量、静态初始化块)=> 子类的(静态变量、静态初始化块)=> 父类的(变量、初始化块、构造器)=> 子类的(变量、初始化块、构造器)
      3、(静态)变量和(静态)代码块的也是有执行顺序的,与代码书写的顺序一致。在(静态)代码块中可以使用(静态)变量,但是被使用的(静态)变量必须在(静态)代码块前面声明。
      *
      *
    • */
      static {
      INSTANCE = new _02hungry();
      }
      private _02hungry() {};
      public static _02hungry getInstance(){
      return INSTANCE;
      }

    public void sayHello(){
    System.out.println(“02hungry”);
    }

    public static void main(String[] args) {
    // _01hungry hungry01 = new _01hungry();
    // _01hungry hungry02 = new _01hungry();
    _01hungry hungry01 = _01hungry.getInstance();
    _01hungry hungry02 = _01hungry.getInstance();
    System.out.println(hungry01==hungry02);
    }
    }

懒汉模式01 最简线程不安全版

顺带复习了线程创建的方式 和lamda 函数
package xzc._01singleton;

/*
** 懒汉模式

    • 1.定义放单例的静态变量
  • 2.构造方法私有化

  • 3.取出单例的静态化方法

  • 解决了自动创建的问题 反而带来了线程这个更大的的问题

  • */
    public class _03LazySingleton {
    private static _03LazySingleton INSTANCE;

    private _03LazySingleton() {
    }

    public static _03LazySingleton getInstance(){
    if (INSTANCE ==null){

          try {
              Thread.sleep(10);
          }catch (InterruptedException e){
              e.printStackTrace();
          }
          INSTANCE = new _03LazySingleton();
    
      }
          return INSTANCE;
    

    }

    public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i<50; i++){
    // 1 继承 Thread重写runable方法
    // MyThread myThread = new MyThread();
    // myThread.sleep(i);
    // myThread.start();

// 2.1实现runnable方法

// Thread myThread = new Thread(new MyThreadRunnable());
// myThread.start();

// 2.2实现runnable方法 匿名内部类 拿来当参数的类,只需要使用一次
// 匿名内部类也就是没有名字的内部类
// 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
// 但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
// new Thread(new MyThreadRunnable(){
// @Override
// public void run() {
// System.out.println(Thread.currentThread().getName() +“xxxx”+ _03LazySingleton.getInstance().hashCode());
// }
// }).start();

// 2.3实现runnable方法 匿名内部类 加lamda方法

// Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
// Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
// 使用 Lambda 表达式可以使代码变的更加简洁紧凑
// 这里只是实现了了一个run方法可以更加简写 为了更加清楚 这里cv2.2代码来简写

// new Thread(new MyThreadRunnable(){
new Thread(()->{
// @Override
// public void run() {
System.out.println(Thread.currentThread().getName() +"—"+ _03LazySingleton.getInstance().hashCode());
// }
}).start();

    }
}

}

///1/
//class MyThread extends Thread {
// @Override
// public void run() {
// System.out.println(Thread.currentThread().getName() +"—"+ _03LazySingleton.getInstance().hashCode());
// }
//}
///2.1/
//class MyThreadRunnable implements Runnable {
// @Override
// public void run() {
// System.out.println(Thread.currentThread().getName() +"—"+ _03LazySingleton.getInstance().hashCode());
// }
//}

懒汉模式02 synchronized 加instance方法版

package xzc._01singleton;
/*
** 懒汉模式 加synchronized版

    • 1.定义放单例的静态变量
  • 2.构造方法私有化

  • 3.取出单例的静态化方法

  • 解决了自动创建的问题 反而带来了线程这个更大的的问题

  • 解决这个问题 加锁 只有一行 再原来的基础上多加个 synchronized 去修饰 getInstance方法

  • 问题解决了 但是代价是性能降低了

  • */
    public class _04LazySingletonSynchronized {
    private static _04LazySingletonSynchronized INSTANCE;

    private _04LazySingletonSynchronized() {
    }

    public static synchronized _04LazySingletonSynchronized getInstance(){
    if (INSTANCE ==null){

          try {
              Thread.sleep(10);
          }catch (InterruptedException e){
              e.printStackTrace();
          }
          INSTANCE = new _04LazySingletonSynchronized();
    
      }
          return INSTANCE;
    

    }

    public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i<50; i++){
    new Thread(()->{
    System.out.println(Thread.currentThread().getName() +"—"+ _04LazySingletonSynchronized.getInstance().hashCode());
    }).start();

      }
    

    }
    }

懒汉模式03 synchronized兼顾安全与性能双重校验锁

package xzc._01singleton;

/*
*

  • 解决了自动创建的问题 反而带来了线程这个更大的的问题

  • 解决这个问题 加锁 只有一行 再原来的基础上多加个 synchronized 去修饰 getInstance方法

  • 问题解决了 但是代价是性能降低了

  • 性能降低了很大的原因是锁的范围太大了 那就减少锁的范围吧 把锁精确放到代码块–不够精确的话···锁没用或者耗费更多的性能在锁上

  • 因为这里没用 因为if判断和 和锁里面的代码块没有一体化

  • 做个双重检查吧

  • 为啥判断两次?

  • 第一次要判断 看起来多了一个判断的性能消耗 但是要考虑到大多数情况下都是null直接返回,可以省出来上锁解锁的消耗 其实是一种优化。

  • 第二次判断保证单例

  • */
    public class _05LazySingletonSynchronized02 {
    private static _05LazySingletonSynchronized02 INSTANCE;

    private _05LazySingletonSynchronized02() {
    }

    public static _05LazySingletonSynchronized02 getInstance(){
    // if (INSTANCE ==null){
    synchronized(_05LazySingletonSynchronized02.class){
    if (INSTANCE ==null){//里面再重新检查一遍
    try {
    Thread.sleep(10);
    }catch (InterruptedException e){
    e.printStackTrace();
    }
    INSTANCE = new _05LazySingletonSynchronized02();
    }
    }

// }
return INSTANCE;
}

public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i<50; i++){
        new Thread(()->{
                System.out.println(Thread.currentThread().getName() +"---"+ _05LazySingletonSynchronized02.getInstance().hashCode());
        }).start();

    }
}

}

静态内部类版 (最完美版 比01好)

package xzc._01singleton;

/*

  • 利用了classloader的机制来保证初始化instance时只有一个线程,(虚拟机加载classloader只会加载一次)
  • 所以也是线程安全的,同时没有性能损耗,所以一般我倾向于使用这一种。
  • 最完美的写法
  • */
    public class _06LazyStaticInnerClass{
    private _06LazyStaticInnerClass(){}
    private static final _06LazyStaticInnerClass INSTANCE=new _06LazyStaticInnerClass();
    public static _06LazyStaticInnerClass getInstance(){
    return _06LazyStaticInnerClass.INSTANCE;
    }
    }

终极版 枚举(java作者推荐)

package xzc._01singleton;

public enum _07SingletonByEnum {
INSTANCE;
public void m(){
System.out.println(“完美中的完美实现单例 不仅解决单例 还解决反序列化”);
}
public static void main(String[] args) {
for (int i = 0; i<50; i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName() +"—"+ _07SingletonByEnum.INSTANCE.hashCode() +"—");
// _07SingletonByEnum.INSTANCE.m();
}).start();

    }
}

}

在spring的xml配置bean中值得注意的地方

1)当scope的取值为singleton时
Bean的实例化个数:1个
Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
Bean的生命周期:
对象创建:当应用加载,创建容器时,对象就被创建了
对象运行:只要容器在,对象一直活着
对象销毁:当应用卸载,销毁容器时,对象就被销毁了
2)当scope的取值为prototype时
Bean的实例化个数:多个
Bean的实例化时机:当调用getBean()方法时实例化Bean
对象创建:当使用对象时,创建新的对象实例
对象运行:只要对象在使用中,就一直活着
对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值