单例模式与多线程

  单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
  1.)某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
  2.)省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
  3.)有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程
  
1、使用静态内置类实现单例模式

public class Singleton {
    private Singleton(){
    }

    private static final Singleton singleton = new Singleton();

    public static Singleton getInstance() {
        return singleton;
    }
}
public class Singleton {
    /* 私有构造方法,防止被实例化 */
    private Singleton() {
    }

    /* 此处使用一个内部类来维护单例 */
    private static class SingletonFactory {
        private static Singleton instance = new Singleton();
    }

    /* 获取实例 */
    public static Singleton getInstance() {
        return SingletonFactory.instance;
    }

    /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */  
    public Object readResolve() {  
        return getInstance();  
    }  
}

自定义线程

public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(Singleton.getInstance().hashCode());
    }
}
public class Run {
    public static void main(String[] args) throws ParseException {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
    }
}

1756075494
1756075494
1756075494

2、序列化与反序列化的单例模式实现
  静态内置类可以达到线程安全问题,但如果遇到序列化对象时,使用默认的方式运行得到的结果还是多例的。

public class Singleton implements Serializable{
    /* 私有构造方法,防止被实例化 */
    private Singleton() {
    }

    /* 此处使用一个内部类来维护单例 */
    private static class SingletonFactory {
        private static Singleton instance = new Singleton();
    }

    /* 获取实例 */
    public static Singleton getInstance() {
        return SingletonFactory.instance;
    }

    /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
    protected Object readResolve() throws ObjectStreamException{
        System.out.println("调用了readResolve方法");
        return getInstance();
    }
}

创建业务类SaveAndRead,代码如下:

public class SaveAndRead {
    public static void main(String[] args)  {
        try {
            Singleton singleton = Singleton.getInstance();
            FileOutputStream fosRef = new FileOutputStream(new File("mySingletonFIle.txt"));
            ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
            oosRef.writeObject(singleton);

            oosRef.close();
            fosRef.close();
            System.out.println(singleton.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try{
            FileInputStream fisRef = new FileInputStream(new File("mySingletonFIle.txt"));
            ObjectInputStream iosRef = new ObjectInputStream(fisRef);
            Singleton singleton = (Singleton) iosRef.readObject();
            iosRef.close();
            fisRef.close();
            System.out.println(singleton.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

723635264
调用了readResolve方法
723635264
如果把Singleton类里的readResolve方法注释掉,则结果会是这样的
1484511730
588729095
不是同一个对象

3、使用static代码块实现单例模式
  静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码块的这个特性来实现单例设计模式。

public class Singleton {
    /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
    private static Singleton instance = null;

    /* 私有构造方法,防止被实例化 */
    private Singleton() {
    }

    static {
        instance = new Singleton();
    }

    public static Singleton getInstance() {
        return instance;
    }
}

自定义线程MyThread和Run类不变,结果如下:
1032010069
1032010069
1032010069

4、使用enum枚举数据类型实现单例模式
  枚举enum和静态代码块的特性相似,在使用枚举类时,构造方法会被自动调用,也可以应用其这个特性实现单例设计模式,最经典的就是数据库连接。

public class Singleton {
    // 枚举类要放单例里防止暴露,不然就违反了“职责单一原则”
    public enum MySingleton {
        connectionFactory;
        private Connection connection;

        private MySingleton() {
            try {
                System.out.print("调用了Singleton的构造!");
                String url = "jdbc:sqlserver://localhost:1079;databaseNme=DB";
                String username = "123456";
                String password = "123456";
                String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
                Class.forName(driverName);
                connection = DriverManager.getConnection(url, username,password);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        public Connection getConnection() {
            return connection;
        }
    }

    public static Connection getConnection() {
        return MySingleton.connectionFactory.getConnection();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值