十四、JAVA多线程笔记:七种单例模式设计

一、恶汉模式   (线程安全)

instance作为类变量,并且直接得到初始化

public class Singleton01{
    //创建静态变量并进行初始化,并且jvm加载时就会进行实例,保证该实例只有一个
    //但是对于多线程而言,这样的效率并不高,造成资源的浪费
    private static final  Singleton01 instance = new Singleton01();
    private Singleton01(){}//将构造函数访问权限修改成private,即外部无法通过new进行实例化调用
    public static Singleton01 getInstance(){
        return instance;
    }

二、懒汉式(非线程安全)

在使用类实例的时候再去创建

//解决了饿汉式的资源浪费的缺点,但是只能在单线程下进行,如果多线程下会不安全,容易被实例化多次
public class Singleton02{
    //创建静态变量,但不初始化,等待使用时进行初始化
    private static Singleton02 instance=null;
    private Singleton02(){}
    
    public static Singleton02 getInstance(){
        if(instance==null){
            instance=new Singleton02();
        }
        return instance;
    }
}

三、懒汉式+同步方法//该线程安全版本,是在初始化方法上加上同步机制synchronized,是的线程安全,但是这种全局同步,会
使得在多线程并发情况下,执行效率不高,故而不推荐

public class Singleton03 {

    private static Singleton03 instance=null;
    private Singleton03(){}

    // 加入 synchronized
    private synchronized Singleton03 getInstance(){
        if(instance==null){
            instance=new Singleton03();
        }
        return instance;
    }
    

}

四、Double-Check(容易引起空指针异常,线程安全

会引起类成员变量的实例化conn和socket放生在instance实例化之后。由于JVM运行时指令重排导致。

//该线程安全版本,是在线程不安全版本上,使用静态块初始化instance实例,通过静态变量jvm初始化规则
静态变量/静态块-非静态变量/构造块-构造函数

package com.zl.step14;


import java.net.Socket;
import java.sql.Connection;

public class Singleton04 {

    private static Singleton04 instance=null;


    Connection conn ;

    Socket socket ;


    private Singleton04(){
        this.conn  = null ;  // 初始化conn
        this.socket = null  ; // 初始化socket

    }


    // 加入 synchronized
    private static Singleton04 getInstance(){
        if(instance==null){
            synchronized (Singleton04.class) {
                if(instance==null){
                    instance=new Singleton04();
                }
            }

        }
        return instance;
    }

    
}

五、 Volatile+Double-Cheack

Double-Cheack会引起类成员变量的实例化conn和socket放生在instance实例化之后。由于JVM运行时指令重排导致。

volatile关键字可以防止这种重排序的发生。

修改代码:

                       private volatile static Singleton05 instance=null;

package com.zl.step14;


import java.net.Socket;
import java.sql.Connection;

public class Singleton05 {

    private volatile static Singleton05 instance=null;


    Connection conn ;

    Socket socket ;


    private Singleton05(){
        this.conn  = null ;  // 初始化conn
        this.socket = null  ; // 初始化socket

    }


    // 加入 synchronized
    private static Singleton05 getInstance(){
        if(instance==null){
            synchronized (Singleton05.class) {
                if(instance==null){
                    instance=new Singleton05();
                }
            }

        }
        return instance;
    }
 
}

六、Holder方式

/**
 * 在Singleton类中并没有instance的静态成员,
 * 而是将其放到了静态内部类Holder之中
 * 因为在Singleton创建的时候,并不会创建Singleton的实例
 * Holder类中定义了Singleton的惊天变量,并且直接进行实例化
 * 当Holder被主动引用的时候就会创建Singleton的实例
 * Singleton实例的创建过程在Java程序编译时期手机至<clint>()方法中
 * 该方法又是同步方法,同步方法可以保证内存的可见性、JVM指令的顺序性和原子性
 *
 *
 */
public class Singleton06 {
    private static final class SingletonHolder{
        private static final Singleton06 instance=new Singleton06();
    }
    private Singleton06(){}
    public static Singleton06 getInstance(){
        return SingletonHolder.instance;
    }

    
}

七、枚举方式

public class Singleton07 {

    private Singleton07(){}
    private static Singleton07 getInstance(){

        return SingletonHolder.INSTANCE.getInstance();
    }
    public enum SingletonHolder{
        INSTANCE;

        private Singleton07 instance=null;

        SingletonHolder(){
            instance=new Singleton07();
        }

        public Singleton07 getInstance(){
            return instance;
        }
    }

    
}

猜你喜欢

转载自blog.csdn.net/zhanglong_4444/article/details/86233201
今日推荐