单例模式-懒汉式的四种方案

饿汉式

饿汉式的代码很简单也不是我们的重点。

package singleton_k;/*
 * @auther 顶风少年
 * @mail [email protected]
 * @date 2020-01-15 20:41
 * @notify
 * @version 1.0
 */

public class Computer {

    private Computer() {
    }

    private static Computer computer = new Computer();

    public static Computer getInstance() {
        return computer;
    }
}
View Code

懒汉式-同步锁

这种synchronized关键字的做法是很最简单的,但是性能较差,对象的创建实际只有一次,剩下的其实都是获取,但是却要在获取时也要同步。

package singleton_k;/*
 * @auther 顶风少年
 * @mail [email protected]
 * @date 2020-01-15 20:41
 * @notify
 * @version 1.0
 */

public class Computer2 {

    private Computer2() {
    }

    private static Computer2 computer = null;

    public static synchronized Computer2 getInstance() {
        if (computer == null) {
            computer = new Computer2();
        }
        return computer;
    }
}
View Code

懒汉式-双检查锁

synchronized转移到方法中,假如有10条线程进入方法内,如果判断==null,也只能有一个线程进入同步代码块,进入代码块后再次判断是否==null第一个线程会将对象实例化。而后来的9条线程判断!=null就不会再次创建。第二次再来10条线程,则第一个if判断都不会通过,所以不会进入synchronized代码块也不会造成线程串行。大大的解决的性能问题。

package singleton_k;/*
 * @auther 顶风少年
 * @mail [email protected]
 * @date 2020-01-15 20:41
 * @notify
 * @version 1.0
 */

public class Computer3 {

    private String name = "张三";

    private Computer3() {
    }

   
    private static  Computer3 computer = null;

    public static Computer3 getInstance() {
        //第二个线程判断对象不为null
        if (computer == null) {
            synchronized (Computer3.class) {
                if (computer == null) {
                    computer = new Computer3();
                }
            }
        }
        return computer;
    }
}
View Code

但是这里还会有一点问题,如果在第一个线程new之后,但是没有初始化成员变量。第二个线程在第一次判断这时已经不是null了,它走到打印处,可能会没有值。所以使用volatile关键字。这个关键字的作用禁止CPU使用缓存,禁止指令重排序。

package singleton_k;/*
 * @auther 顶风少年
 * @mail [email protected]
 * @date 2020-01-15 20:41
 * @notify
 * @version 1.0
 */

public class Computer3 {

    private String name = "张三";

    private Computer3() {
    }

    /*
    volatile
    作用1 禁止被他修饰变量发生指令重排序
    作用2 禁止CPU使用缓存
    * */
    private static volatile Computer3 computer = null;

    public static Computer3 getInstance() {
        //第二个线程判断对象不为null
        if (computer == null) {
            synchronized (Computer3.class) {
                if (computer == null) {
                    /*1 new:开辟内存空间
                     * 2 成员变量初始化
                     * 3 将内存中的地址赋值给变量
                     * 此处2和3可能指令重排序
                     * */
                    //第一个线程执行完下边这一句new出来了。
                    computer = new Computer3();
                }
            }
        }
        //此处可能会出错,出错了。线程1的指令重排序是132但是2还没执行就拿不到这个变量的值了
        System.out.println(computer.name);
        return computer;
    }
}
View Code

懒汉式-静态内部类

通过静态内部类的方式实现单例模式是线程安全的,同时静态内部类不会在Singleton类加载时就加载,而是在调用getInstance()方法时才进行加载,达到了懒加载的效果。

package singleton_k;/*
 * @auther 顶风少年
 * @mail [email protected]
 * @date 2020-01-15 20:41
 * @notify
 * @version 1.0
 */

public class Computer4 {

    private Computer4() {
    }

    /*
    * 通过内部类维护单例JVM在类加载的时候,是互斥的,所以可以保证线程安全问题
    * */
    private static class Computer4Factory{
        private static Computer4 computer4 = new Computer4();
    }

    public static Computer4 getComputer(){
        return Computer4Factory.computer4;
    }

}
View Code

懒汉式-枚举

利用枚举的特性,让JVM来帮我们保证线程安全和单一实例的问题。除此之外,写法还特别简单。

package singleton_k;/*
 * @auther 顶风少年
 * @mail [email protected]
 * @date 2020-01-15 20:41
 * @notify
 * @version 1.0
 */

public enum  Computer4 {
    INSTANCE;
    public void show(){
        System.out.println(".....");
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/zumengjie/p/12198758.html