一、单例模式简介

  单例模式是Java设计模式中常见的一种模式。主要分为懒汉式单例、饿汉式单例、登记式单例;

  单例模式的特点:  1、单例类只能有一个实例;  2、单例类必须自己创建自己的唯一的实例; 3、单例类必须给所有其他对象提供这一实例;

二、饿汉式单例 

  1. public class SingleTonModel {
  2.  
  3. private SingleTonModel(){}
  4. private static final SingleTonModel singt=new SingleTonModel();
  5.  
  6. public static SingleTonModel getInstance(){
  7. return singt;
  8. }
  9. }

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

三、懒汉式单例

  简单的例子:

  1. public class SingleTonModel {
  2.  
  3. private SingleTonModel(){}
  4. private static SingleTonModel singt=null;
  5.  
  6. public static SingleTonModel getInstance(){
  7. if(singt==null){
  8. singt=new SingleTonModel();
  9. }
  10. return singt;
  11. }
  12. }
Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。

(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)

但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全:(课外知识可以了解线程安全)

  改造一:在静态方法上添加关键词:synchronized,进行同步

  1. public class SingleTonModel {
  2.  
  3. private SingleTonModel(){}
  4. private static SingleTonModel singt=null;
  5.  
  6. public static synchronized SingleTonModel getInstance(){
  7. if(singt==null){
  8. singt=new SingleTonModel();
  9. }
  10. return singt;
  11. }
  12. }

  虽然通过同步保障了线程安全,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的。

改造二:在判断不存在实例时才进行同步

  1. public class SingleTonModel {
  2.  
  3. private SingleTonModel(){}
  4. private static SingleTonModel singt=null;
  5.  
  6. public static SingleTonModel getInstance(){
  7. if(singt==null){
  8. synchronized(SingleTonModel.class){
  9. if(singt==null){
  10. singt=new SingleTonModel();
  11. }
  12. }
  13. }
  14. return singt;
  15. }
  16. }

  在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗。

改造三:添加内部静态类

  1. public class SingleTonModel {
  2.  
  3. private SingleTonModel(){}
  4.  
  5. private static class lanSingleton{
  6. private static final SingleTonModel singt=new SingleTonModel();
  7. }
  8.  
  9. public static final SingleTonModel getInstance(){
  10. return lanSingleton.singt;
  11. }
  12. }

利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗,所以一般我倾向于使用这一种。

四、登记式单例(很少用)

  1. /类似Spring里面的方法,将类名注册,下次从里面直接获取。
  2. public class Singleton3 {
  3. private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();
  4. static{
  5. Singleton3 single = new Singleton3();
  6. map.put(single.getClass().getName(), single);
  7. }
  8. //保护的默认构造子
  9. protected Singleton3(){}
  10. //静态工厂方法,返还此类惟一的实例
  11. public static Singleton3 getInstance(String name) {
  12. if(name == null) {
  13. name = Singleton3.class.getName();
  14. System.out.println("name == null"+"--->name="+name);
  15. }
  16. if(map.get(name) == null) {
  17. try {
  18. map.put(name, (Singleton3) Class.forName(name).newInstance());
  19. } catch (InstantiationException e) {
  20. e.printStackTrace();
  21. } catch (IllegalAccessException e) {
  22. e.printStackTrace();
  23. } catch (ClassNotFoundException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. return map.get(name);
  28. }
  29. //一个示意性的商业方法
  30. public String about() {
  31. return "Hello, I am RegSingleton.";
  32. }
  33. public static void main(String[] args) {
  34. Singleton3 single3 = Singleton3.getInstance(null);
  35. System.out.println(single3.about());
  36. }
  37. }

  登记式单例实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。

课外小知识:

  1、什么是线程安全

  如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

  或者说:一个类或者程序所提供的接口对于线程来说是原子操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题,那就是线程安全的。

  

Java23种设计模式之单例模式的更多相关文章

  1. java23种设计模式之一: 单例模式(Singleton Pattern)

    单例模式(Singleton Pattern)是设计模式中比较常用的一种,下面来总结单例模式的知识,包括: 1.理解什么是单例模式.单例模式有什么优点/缺点.单例模式的应用场景: 2.再来看看Java ...

  2. java23种设计模式——四、原型模式

    源码在我的github和gitee中获取 目录 java23种设计模式-- 一.设计模式介绍 java23种设计模式-- 二.单例模式 java23种设计模式--三.工厂模式 java23种设计模式- ...

  3. java23种设计模式—— 一、设计模式介绍

    Java23种设计模式全解析 目录 java23种设计模式-- 一.设计模式介绍 java23种设计模式-- 二.单例模式 java23种设计模式--三.工厂模式 java23种设计模式--四.原型模 ...

  4. java23种设计模式——五、建造者模式

    源码在我的github和gitee中获取 目录 java23种设计模式-- 一.设计模式介绍 java23种设计模式-- 二.单例模式 java23种设计模式--三.工厂模式 java23种设计模式- ...

  5. java23种设计模式——八、组合模式

    目录 java23种设计模式-- 一.设计模式介绍 java23种设计模式-- 二.单例模式 java23种设计模式--三.工厂模式 java23种设计模式--四.原型模式 java23种设计模式-- ...

  6. java23种设计模式——七、桥接模式

    原文地址:https://www.cnblogs.com/chenssy/p/3317866.html 源码在我的github和gitee中获取 目录 java23种设计模式-- 一.设计模式介绍 j ...

  7. java23种设计模式 (转)

    文章在:http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html 随着自己的开发经验增加以及自己做了很多的 大专栏  jav ...

  8. java23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  9. 学习java23种设计模式自我总结

    首先先做个广告,以前看过@maowang 这位大神转的Java开发中的23种设计模式详解(转) ,但是看了之后都忘差不多了, 所以,开个帖子边学习边自我总结(纯手敲).一直以来像这种需要长久的运动,真 ...

随机推荐

  1. (转载)php循环检测目录是否存在并创建(循环创建目录)

    (转载)http://www.jb51.net/article/25917.htm php循环检测目录是否存在并创建,需要的朋友可以参考下. 循环创建目录方法 这个会生成image.gif目录 代码如 ...

  2. Devexpress 之gridControl

    1.gridControl如何去掉主面板? 鼠标右键Run Designer=>OptionsView => ShowGroupPanel=False: 2.gridControl如何设置 ...

  3. ARM学习笔记3——数据处理指令

    一.数据处理指令概述 1.概念 数据处理指令是指对存放在寄存器中的数据进行处理的指令.主要包括算术指令.逻辑指令.比较与测试指令以及乘法指令 如果在数据处理指令前使用S前缀,指令的执行结果将会影响CP ...

  4. 作品第二课----点击DIV显示其内容

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. [Ruby on Rails Issue] When Setting Sqlite version on the Gemfile, Show error "An error occurred while installing sqlite3 ",

    Issue: Gem files will remain installed in /tmp/bundler20140825-31835-p0c0p/sqlite3-1.3.9/gems/sqlite ...

  6. dd usb 启动盘制作 成功版本

    在linux系统中,使用dd命令制作启动盘成功.方法是在终端中输入命令:     dd if=/root/opensuse.iso of=/dev/sdb bs=4M     说明:      1.o ...

  7. nyoj 483 Nightmare【bfs+优先队列】

    Nightmare 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 Ignatius had a nightmare last night. He found him ...

  8. [学习笔记]设计模式之Abstract Factory

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在上篇笔记Builder设计模式中,时の魔导士祭出了自己的WorldCreator.尽管它因此能创造出一个有山有树有房子的世界,但是白 ...

  9. tar linux 打包 压缩 gzip 命令说明

    参数:-c  :建立一个压缩档案的参数指令(create 的意思):-x  :解开一个压缩档案的参数指令!-t  :查看 tarfile 里面的档案!      特别注意,在参数的下达中, c/x/t ...

  10. URAL 1146 Maximum Sum(最大子矩阵的和 DP)

    Maximum Sum 大意:给你一个n*n的矩阵,求最大的子矩阵的和是多少. 思路:最開始我想的是预处理矩阵,遍历子矩阵的端点,发现复杂度是O(n^4).就不知道该怎么办了.问了一下,是压缩矩阵,转 ...