java单例模式,单例模式懒汉和饿汉( 二 )


某类需要频繁实例化 , 而创建的对象又频繁被销毁的时候 , 如多线程的线程池、网络连接池等 。频繁访问数据库或文件的对象 。对于一些控制硬件级别的操作 , 或者从系统上来讲应当是单一控制逻辑的操作 , 如果有多个实例 , 则系统会完全乱套 。当对象需要被共享的场合 。由于单例模式只允许创建一个对象 , 共享该对象可以节省内存 , 并加快对象访问速度 。
如 Web 中的配置对象、数据库的连接池等 。单例模式的结构与实现单例模式是设计模式中最简单的模式之一 。通常 , 普通类的构造函数是公有的 , 外部类可以通过“new 构造函数()”来生成多个实例 。但是 , 如果将类的构造函数设为私有的 , 外部类就无法调用该构造函数 , 也就无法生成多个实例 。这时该类自身必须定义一个静态私有实例 , 并向外提供一个静态的公有函数用于创建或获取该静态私有实例 。
下面来分析其基本结构和实现方法 。1. 单例模式的结构单例模式的主要角色如下 。单例类:包含一个实例且能自行创建这个实例的类 。访问类:使用单例的类 。其结构如图 1 所示 。图1 单例模式的结构图2. 单例模式的实现Singleton 模式通常有两种实现形式 。第 1 种:懒汉式单例该模式的特点是类加载时没有生成单例 , 只有当第一次调用 getlnstance 方法时才去创建这个单例 。
代码如下:public class LazySingleton {private static volatile LazySingleton instance = null;//保证 instance 在所有线程中同步private LazySingleton() {}//private 避免类在外部被实例化public static synchronized LazySingleton getInstance() {//getInstance 方法前加同步if (instance == null) {instance = new LazySingleton();}return instance;}}注意:如果编写的是多线程程序 , 则不要删除上例代码中的关键字 volatile 和 synchronized , 否则将存在线程非安全的问题 。
如果不删除这两个关键字就能保证线程安全 , 但是每次访问时都要同步 , 会影响性能 , 且消耗更多的资源 , 这是懒汉式单例的缺点 。第 2 种:饿汉式单例该模式的特点是类一旦加载就创建一个单例 , 保证在调用 getInstance 方法之前单例已经存在了 。public class HungrySingleton {private static final HungrySingleton instance = new HungrySingleton();private HungrySingleton() {}public static HungrySingleton getInstance() {return instance;}}饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用 , 以后不再改变 , 所以是线程安全的 , 可以直接用于多线程而不会出现问题 。
单例模式的应用实例【例1】用懒汉式单例模式模拟产生美国当今总统对象 。分析:在每一届任期内 , 美国的总统只有一人 , 所以本实例适合用单例模式实现 , 图 2 所示是用懒汉式单例实现的结构图 。图2 美国总统生成器的结构图程序代码如下:public class SingletonLazy {public static void main(String[] args) {President zt1 = President.getInstance();zt1.getName();//输出总统的名字President zt2 = President.getInstance();zt2.getName();//输出总统的名字if (zt1 == zt2) {System.out.println("他们是同一人!");} else {System.out.println("他们不是同一人!");}}}class President {private static volatile President instance = null;//保证instance在所有线程中同步//private避免类在外部被实例化private President() {System.out.println("产生一个总统!");}public static synchronized President getInstance() {//在getInstance方法上加同步if (instance == null) {instance = new President();} else {System.out.println("已经有一个总统 , 不能产生新总统!");}return instance;}public void getName() {System.out.println("我是美国总统:特朗普 。

推荐阅读