1.单例模式

单例模式

  • 定义:程序运行时,在java虚拟机中只存在该类的一个实例对象。
  • demo:
package mode;

public class SingleDemo {
    // 创建SingleDemo单例对象
    private static SingleDemo instance = new SingleDemo();
    // 将构造方法设成私有的,这样该类就不会被实例化
    private SingleDemo() {}

    public static SingleDemo getInstance() {
        return instance;
    }

    public void showMessage() {
        System.out.println("这里是重要的信息");
    }
}
class SingleAply{
    public static void main(String[] args) {
        SingleDemo singleDemo = SingleDemo.getInstance();
        singleDemo.showMessage();
    }
}

实现方式

懒汉式-线程不安全

懒汉式_线程不安全
优点 1.起到了延迟加载的效果
缺点 1.只能在单线程下使用
2.如果在多线程下,一个线程进入了if(single==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这是便会产生多个实例。所以多线程不可以使用
结论 在实际开发中,不要使用这种方式
public class LazyNotSafe {
    private static LazyNotSafe instance;
    private LazyNotSafe() {}

    public LazyNotSafe getInstance() {
        if (instance == null) {
            instance = new LazyNotSafe();
        }
        return instance;
    }
}

懒汉式-线程安全

懒汉式_线程安全
优点 1.解决了线程不安全问题
缺点 1.效率太低,每个线程在想获得类的实例的时候,执行getInstance()方法都要进行同步。
2.而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低。
结论 在实际开发中,不要使用这种方式
public class LazySafe {
    private static LazySafe instance;
    private LazySafe() {}

    public static synchronized LazySafe getInstance() {
        if (instance == null) {
            instance = new LazySafe();
        }
        return instance;
    }
}

懒汉式-线程不安全同步代码块

懒汉式_同步代码块
优点 延迟加载
缺点 1.本意是对线程安全的懒汉式进行改进,因为其同步方法效率太低,改为同步产生的实例化代码块
2.线程不能同步。假如一个线程进入了if(instance==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例
注意:synchronized同步代码块中,当释放锁后,会继续向下执行
结论 在实际开发中,不能用这种方式
public class LazyNoSafePiece {
    private static LazyNoSafePiece instance;
    private LazyNoSafePiece() {}

    public LazyNoSafePiece getInstance() {
        if (instance == null) {
            synchronized(LazyNoSafePiece.class) {
                instance = new LazyNoSafePiece();
            }
        }
        return instance;
    }
}

饿汉式-静态变量/静态代码块

饿汉式_静态变量/静态代码块
优点 在类加载的时候完成了实例化,避免了线程同步问题。
缺点 在类装载的时候就完成实例化,没有达到延迟加载的效果。如果从头到尾未使用过这个实例,则会造成内存的浪费
结论 这种单例模式可以使用,但可能会造成内存的浪费
class HungrySafe {
    private static HungrySafe instance = new HungrySafe();
    private HungrySafe() {}
    public static HungrySafe getInstance() {
        return instance;
    }
}

class HungrySafe2 {
    private static HungrySafe2 instance;
    private HungrySafe2() {}
    static {
        instance = new HungrySafe2();
    }
    public static HungrySafe2 getInstance() {
        return instance;
    }
}

双重检查(推荐使用)

双重检查
优点 1.线程安全
2.延迟加载
3.效率较高
4.实例化代码只用执行一次,后面再次访问时,判断第一层if(xxx==null),直接return实例化对象,也避免的反复进行方法同步。
结论 在实际开发中,推荐使用
public class DoubleCheck {
    private DoubleCheck doubleCheck;
    private DoubleCheck() {}
    
    public DoubleCheck getInstance() {
        if (doubleCheck == null) {
            synchronized(DoubleCheck.class) {
                if (doubleCheck == null) {
                    doubleCheck = new DoubleCheck();
                }
            }
        }
        return doubleCheck;
    }
}

静态内部类(推荐使用)

优势
如何保证实例时只有一个线程?
即如何保证线程安全?
类的静态属性只会在第一次加载类的时候初始化,在类进行初始化时,别的线程是无法进入的,所以线程安全
如何实现延迟加载 利用静态内部类,不是在xxx类被装载时立即实例化,而是在调用getInstance方法时,才会装载xxx类,从而完成xxx类的实例化
public class InnerClass {
    // volatile:一有修改就更新到主存中去
    private static volatile InnerClass instance;
    private InnerClass() {}

    private static class InnerInstance {
        private final static InnerClass instance = new InnerClass();
    }

    public static InnerClass getInstance() {
        return InnerInstance.instance;
    }
}

枚举

枚举
优点 1.能避免多线程同步问题
2.自动支持序列化机制,防止反序列化重新创建新的对象,防止多次实例化。
注意1:枚举类的内部定义的枚举值就是该类的实例(且必须在第一行定义,当类初始化时,这些枚举值会被实例化)。
线程安全由于JVM保证,因为ClassLoader进行类加载时,加了同步锁synchronized。
注意2:枚举类型在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象,而不是通过调用 readObject()方法来返回一个新创建出来的对象。同时,编译器是不允许任何对这种序列化机制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。
enum EnumSingleton {
    INSTANCE;
    public void sayOK() {
        System.out.println("ok");
    }
}

class A {
    public static void main(String[] args) {
        System.out.println(EnumSingleton.INSTANCE);
        EnumSingleton.INSTANCE.sayOK();
    }
}
posted @ 2023-08-15 17:11  jsqup  阅读(2)  评论(0编辑  收藏  举报