单例模式与多线程
2017-08-27 22:22
169 查看
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
1.)某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2.)省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3.)有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程
1、使用静态内置类实现单例模式
自定义线程
1756075494
1756075494
1756075494
2、序列化与反序列化的单例模式实现
静态内置类可以达到线程安全问题,但如果遇到序列化对象时,使用默认的方式运行得到的结果还是多例的。
创建业务类SaveAndRead,代码如下:
723635264
调用了readResolve方法
723635264
如果把Singleton类里的readResolve方法注释掉,则结果会是这样的
1484511730
588729095
不是同一个对象
3、使用static代码块实现单例模式
静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码块的这个特性来实现单例设计模式。
自定义线程MyThread和Run类不变,结果如下:
1032010069
1032010069
1032010069
4、使用enum枚举数据类型实现单例模式
枚举enum和静态代码块的特性相似,在使用枚举类时,构造方法会被自动调用,也可以应用其这个特性实现单例设计模式,最经典的就是数据库连接。
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(); } }
相关文章推荐
- 多线程下的懒汉式单例模式
- 标准Singleton设计模式,多线程下
- 单例模式中的 双重检查锁定(Double-Check Locking ) (多线程下单例模式中的双重检查锁定的实现)
- 多线程编程的设计模式 临界区模式(一)
- 单例模式如何在多线程环境下保证安全—Double Checked Locking 模式使用
- java多线程总结学习-Queue、容器、单例模式
- 多线程-临界区模式
- Java 多线程下的单例模式
- 黑马程序员----------java基础加强之多线程、单例设计模式
- Rhyme/Java 单例模式Singleton的多线程控制与优化
- 学习进度表 +解决单利设计模式懒汉式在多线程的安全问题
- java多线程之消费者生产者模式
- Java 多线程设计模式
- Java多线程之生产者消费者模式
- ASP.NET 环境下的并发与多线程处理及单件模式、事件重入
- 设计模式-单例模式之饿汉式-多线程
- 多线程设计模式——Half-sync/Half-async(半同步/半异步)模式
- 多线程程序设计学习(9)worker pattern模式
- 多线程等待唤醒机制之生产消费者模式