温故而知新 设计模式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();

    }
}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章