【Java设计模式】1.单例模式

写在前面

Java设计模式总共有23种,虽然我也没仔细数。单例模式,好像在常用的Java项目中必不可少吧,好比是做米饭绝对少不了米,没毛病。这里谈谈自己的理解吧,大致分为几个方面:

1.哪些时候需要用到单例模式,即单例模式的使用场景,谈谈Singleton Mode的概念

2.常见有哪几种单例模式

3.单例模式的好处

4.单例模式和线程安全的那些事儿

1.0 什么时候需要单例模式

1.1 定义

单例模式,是一种创建对象的设计模式,单例模式确保其某一个类只有一个实例,即:它要确保整个类有且只有一个可供外界调用的实例化方法,并自动实例化,供整个Java项目(系统)的类调用。

这个类:单例类。

1.2 单例模式的使用场景

这里百度下:配置信息类、管理类、控制类、门面类、代理类通常被设计为单例类。像Java的Struts、spring框架,.Net的Spring.NET框架,以及PHP的Zend框架都大量使用了单例模式。

这里贴一个配置信息类代码,是我的项目中用到的全局配置文件

ResourceLoader.java,这个类就是一个单例,用于读取配置文件

 1 package friends.util.common;
 2
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.util.HashMap;
 6 import java.util.Map;
 7 import java.util.Properties;
 8
 9 /**
10  * Created by Samuel on 2017/5/2.
11  *
12  * Singleton mod(lazy-type)
13  *
14  */
15 public class ResourceLoader {
16
17     private static ResourceLoader loader;
18     private static Map<String, Properties> loaderMap = new HashMap<String, Properties>();
19
20     private ResourceLoader() {
21     }
22
23     public static ResourceLoader getInstance() {
24         if(loader==null)
25             loader = new ResourceLoader();
26
27         return loader;
28     }
29
30     public Properties getPropFromProperties(String fileName) throws Exception {
31
32         Properties prop = loaderMap.get(fileName);
33         if (prop != null) {
34             return prop;
35         }
36         String filePath = null;
37         String configPath = System.getProperty("configurePath");
38
39         if (configPath == null) {
40
41             // 加载classes的根目录
42             StringBuffer root_path = new StringBuffer(this.getClass().getClassLoader().getResource("/").getPath());
43
44             //我们的配置文件是放在与classes的同级目录conf下的,故
45             filePath = root_path.append("../conf/").append(fileName).toString();
46
47         } else {
48             filePath = configPath + "/" + fileName;
49         }
50         prop = new Properties();
51         prop.load(new FileInputStream(new File(filePath)));
52
53         loaderMap.put(fileName, prop);
54         return prop;
55     }
56 }

PropertiesUtil.java
package friends.util.common;

import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Created by Samuel on 2017/5/2.
 */
public class PropertiesUtil {

    private static ResourceLoader loader = ResourceLoader.getInstance();
    //存储 配置文件中的k-v
    private static ConcurrentMap<String, String> configMap = new ConcurrentHashMap<String, String>();
    private static final String DEFAULT_CONFIG_FILE = "wxset.properties";

    private static Properties prop = null;

    public static String getStringByKey(String key, String propName) {
        try {
            prop = loader.getPropFromProperties(propName);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        key = key.trim();
        if (!configMap.containsKey(key)) {
            if (prop.getProperty(key) != null) {
                configMap.put(key, prop.getProperty(key));
            }
        }
        return configMap.get(key);
    }

    public static String getStringByKey(String key) {
        return getStringByKey(key, DEFAULT_CONFIG_FILE);
    }

    public static Properties getProperties() {
        try {
            return loader.getPropFromProperties(DEFAULT_CONFIG_FILE);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
Constant.java
 1 package friends.util.common;
 2
 3 /**
 4  * Created by Samuel on 2017/5/2.
 5  *
 6  * 全局常量 的配置
 7  */
 8 public class Constant {
 9
10     /**
11      * 微信的appid
12      */
13     public static final String appid_wx = PropertiesUtil.getStringByKey("appid");
14
15
16 }

综上,想要调用,配置文件中的一些参数,在Constant都定义好了,直接调用即可。

其他的场景我就没法演示了,可能以前遇到多,但是没注意(鄙视自己100次),也许就没碰到过,好吧,言归正题自己侃...

2.常见有哪几种单例模式

Java设计模式有23种,而单例模式的实现方式虽说没那么多,但是也不少,之前看过一篇博文,谈到了7种之多,点这里

这里点一下,Effective Java提到的enum枚举的方式来实现单例模式,这里我就讲讲常用的懒汉式(lazy-type)和饿汉式

2.1  懒汉式

所谓懒汉式,就是很懒了,你不搭理我,我就不干活,说到底就是不自觉啦。代码如上 ResourceLoader.java 中的 loader 预先只是申明,并没有实例化,调用实例化方法getInstance()时才取判断是否实例化情况来实例化,这就是典型的懒汉,为啥是懒汉不是懒鬼,懒婆,一言蔽之:"国际惯例"!

2.2 饿汉式

相比于懒汉式,它自然就是个饿鬼了,一回家,不用别人催它,看到香喷喷的饭菜就吃,我改一下ResourceLoader.java ,贴一下,大家对比下,就知道什么叫饿鬼了,额,饿汉

ResourceLoader2.java

 1 package friends.util.common;
 2
 3 /**
 4  * Created by Samuel on 2017/5/2.
 5  *
 6  * Singleton mod 饿汉式
 7  *
 8  */
 9 public class ResourceLoader2 {
10
11     /**
12      * 申明 私有化 静态实例,仅供实例方法调用
13      */
14     private static ResourceLoader2 loader = new ResourceLoader2();;
15
16     /**
17      * 和 懒汉式一样,私有化构造方法,不让其他类调用
18      */
19     private ResourceLoader2() {
20     }
21
22     public static ResourceLoader2 getInstance() {
23         return loader;
24     }
25
26
27 }

ResourceLoader2.java 中的 loader 在项目启动的时候就直接实例化了(太饿了),调用实例化方法getInstance()时直接获得实例,

3.单例模式的好处

1、控制资源的使用,通过线程同步来控制资源的并发访问

2、控制实例的产生,以达到节约资源的目的

3、控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信

这三点摘自 师哥的总结,后两点我想应该很明显吧,至于第一点,看下面的分解

4.单例模式和线程安全的那些事儿

4.1 懒汉式,是线程不安全的,多线程的情况下是致命的,

4.2 有人说在实现方法getInstance()加上关键字synchronized 不就线程安全了吗?是的,随之带来的,效率太低了

4.3 饿汉模式,是线程安全的,这种方式基于classloder机制避免了多线程的同步问题,但是没有懒加载的效果

这里备注下;之前看过一篇博文,谈到了7种之多,这篇博文中谈到单例模式的2个坑,这里借鉴下,我觉得很重要

1.如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。

2.如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。

对第一个问题修复的办法是:

 1 private static Class getClass(String classname)
 2                                          throws ClassNotFoundException {
 3       ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 4
 5       if(classLoader == null)
 6          classLoader = Singleton.class.getClassLoader();
 7
 8       return (classLoader.loadClass(classname));
 9    }
10 }

对第二个问题修复的办法是:

 1 public class Singleton implements java.io.Serializable {
 2    public static Singleton INSTANCE = new Singleton();
 3
 4    protected Singleton() {
 5
 6    }
 7    private Object readResolve() {
 8             return INSTANCE;
 9       }
10 } 

最后

又无耻的摘了果子,不耻下问,共同学习,向大神敬个礼!

时间: 2024-10-28 00:06:15

【Java设计模式】1.单例模式的相关文章

(九)JAVA设计模式之单例模式

JAVA设计模式之单例模式 一.单例模式的介绍 Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点.     全局对象和Singleton模式有本质的区别,因为大量使用全局对象会使得程序质量降低,而且有些编程语言根本不支持全局变量.最重要的是传统的全局对象并不能阻止一个类被实例化多次. 二.单例模式的特点 单例类只能有一个实例 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例.

java 设计模式之单例模式

--------2015-11-20 14:45:10 java设计模式之单例模式(Singleton): ---应用场合:只需要一个对象就可以了,例如一个朝代一个皇帝. ---作用:保证某个应用程序中某个实例有且只有一个.共同使用一个,节省资源. ---类型:饿汉模式,懒汉模式. 一.饿汉模式(类加载的时候就会实例化,线程安全) 1 package com.sun.singleton; 2 3 //饿汉模式 4 public class Singleton { 5 6 //将构造函数私有化,不

java设计模式之单例模式(Singleton)

Java设计模式之单例模式 单例模式是什么? 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式如何来设计呢? 保证一个类只能有一个实例,那么我们不能无限制的new 来创建,因为我们知道,new一次就是一个新的对象,那么构造器只能私有化private -- 构造器私有化 构造器私有化了,问题又出现了,构造器私有化了,那么我们怎么来创建唯一的对象呢?-- 提供一个公有的方法/提供一个公有的静态属性 再分析一下,公有方法, 实例方法还是类方法呢?--公有的类方法(获取类实例) 依据以上

java设计模式之单例模式(Singleton pattern)

java设计模式之单例模式(Singleton pattern) 单例模式的定义: Singleton pattern restricts the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine. The singleton class must provide a global access point to get the i

Java设计模式之单例模式(七种写法)

Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton { private static Singleton instance; private Singleton (){}//私有化构造方法,防止类被实例化 public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } retu

折腾Java设计模式之单例模式

博文原址:折腾Java设计模式之单例模式 单例模式 Ensure a class has only one instance, and provide a global point of access to it. 一个类仅仅只有一个实例,并且提供全局的接入点.简洁点理解就是涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建.这个类提供了一种访问它自己唯一的对象的方式,可以直接访问,不需要实例化该类的对象. 饿汉式单例模式 public final class EagerSi

Java设计模式:单例模式

概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,但只能

[转]JAVA设计模式之单例模式

原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话

Java 设计模式(3)单例模式

前言 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,

JAVA设计模式之单例模式(转)

本文继续介绍23种设计模式系列之单例模式. 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器