专栏首页CodingBlock设计模式之单例模式

设计模式之单例模式

  无论什么开发中,设计模式都起着关键的作用,其中比较常用的当属单例了,所谓单例,就是让一个类在项目中只存在一个对象,即使用到这个类的地方很多,也只存在一个对象。但是为什么要这样呢,为什么只创建一个对象呢,多个不也行吗?这个就要结合实际来说了,有些对象我们确实只需要一个,比如说线程池、缓存、硬件设备,如果多个实例就可能会导致冲突,出现运行结果不一致的现象。

一、单例的基本框架

  当然,单例有很多种实现形式,最基本的框架大致如下:

 1 /**
 2  * 普通单例:
 3  * 只使用在单一线程,多线程时可能会出现多个对象
 4  * @author 刘伟 2015/10/13
 5  */
 6 public class SimpleSingleTon {
 7     private static SimpleSingleTon instance = null;
 8 
 9     public static SimpleSingleTon getInstance() {
10         if (instance == null) {
11             instance = new SimpleSingleTon();
12         }
13         return instance;
14     }
15 
16     private SimpleSingleTon() {
17     }
18 }

  上面代码即为单例的一个基本的实现形式,很轻松就能看出在程序中首次使用这个类的代码通过getInstance()方法就能实例化这个类从而获得类的对象,但以后再调用getInstance()时就不会实例化,而是直接获得已经存在的对象。

二、单例模式的优化

  这段代码在单一线程中执行是没有问题的,但如果是在多线程中就可能会出现两个或多个对象,试想一下如果恰好有两个线程同时进入了getIntance()得if语句里面,这时候就会实例化两次SimpleSingleTon,因为首次执行getInstance()时instance是null,所以这种情况是可能发生的。那么怎么避免这种情况发生呢,可以使用以下几种方法:

  • 方案一:急切创建对象

  这种方法是直接在单例类里面吧静态变量直接实例化,这样无论是多线程还是单线程都能保证只有一个对象了,缺点就是会对内存造成一定的浪费。

 1 /**
 2  * 单例优化--急切创建对象
 3  * 
 4  * @author codingblock 2015/10/13
 5  */
 6 public class SingleTon {
 7     private static SingleTon instance = new SingleTon();
 8 
 9     public static SingleTon getInstance() {
10         System.out.println("instance:" + instance);
11         return instance;
12     }
13 
14     private SingleTon() {
15 
16     }
17 }
  • 方案二:添加同步锁

  为了在多线程中不让两个线程同时执行getInstance()方法,可以为此方法添加一同步锁,这样就能避免此情况发生了。代码如下:

 1 /**
 2  * 单例优化--添加同步锁
 3  * 可以在多线程中运行
 4  * @author 刘伟 2015/10/13
 5  */
 6 public class SimpleSyncSingleTon {
 7     
 8     private static SimpleSyncSingleTon instance = null;
 9     
10     public static synchronized  SimpleSyncSingleTon getInstance() {
11         if (instance == null) {
12             instance = new SimpleSyncSingleTon();
13         }
14         return instance;
15     }
16     
17     private SimpleSyncSingleTon() {
18     }
19 }

  这样就可以保证在多线程中也只会创建一个对象,但同步锁是比较耗费资源的,如果在程序中频繁地获取对象,这样的话效率就大大地降低了。所以说,在单例中添加同步锁的方法比较适用于对对象获取不是很频繁地情况。

  • 方案三:双重检查加锁法

  首先需要在对象变量前面添加一个volatile关键字,这个是为了通知编译器线程安全用的。然后再getInstance检查两次,具体代码如下:

 1 /**
 2  * 单例优化--双重检查加锁法 
 3  * 可以在多线程中运行
 4  * @author 刘伟 2015/10/13
 5  */
 6 public class CheckAgainSingleTon {
 7 
 8     private volatile static CheckAgainSingleTon instance = null;
 9 
10     public static synchronized CheckAgainSingleTon getInstance() {
11         if (instance == null) {
12             synchronized (CheckAgainSingleTon.class) {
13                 if (instance == null) {
14                     instance = new CheckAgainSingleTon();
15                 }
16             }
17         }
18         return instance;
19     }
20 
21     private CheckAgainSingleTon() {
22     }
23 }

  通过这个方法程序在获取对象时无论怎么样都只会进入加锁区一次,例如最开始两个线程在竞争时,其中一个线程进入了加锁后创建了对象,以后所有的进程在执行getInstance方法时直接判断instance非null,就能直接返回对象了,不需要再进入加锁区了。这样即使程序频繁地获取对象也不会再进入加锁区了,相对第二种方法就大大节省了资源。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 小白也能看懂的插件化DroidPlugin原理(一)-- 动态代理

    前言:插件化在Android开发中的优点不言而喻,也有很多文章介绍插件化的优势,所以在此不再赘述。前一阵子在项目中用到 DroidPlugin 插件框架 ,近...

    codingblock
  • Java数据结构和算法总结-数组、二分查找

    前言:在平时开发中数组几乎是最基本也是最常用的数据类型,相比链表、二叉树等又简单很多,所以在学习数据和算法时用数组来作为一个起点再合适不过了。本篇博文的所有代...

    codingblock
  • Java数据结构和算法总结-字符串相关高频面试题算法

    前言:周末闲来无事,在七月在线上看了看字符串相关算法的讲解视频,收货颇丰,跟着视频讲解简单做了一下笔记,方便以后翻阅复习同时也很乐意分享给大家。什么字符串在算...

    codingblock
  • 如何搭建redis集群 --- redis-cluster

    在之前的《来聊聊NoSql》一文中,已经说了redis三种集群模式中的主从和哨兵,接下来再看看redis-cluster怎么玩。本文基于redis-cluste...

    贪挽懒月
  • 《白蛇•缘起》成功了,但那不是王微想要的

    今日头条丨一点资讯丨腾讯丨搜狐丨网易丨凤凰丨阿里UC大鱼丨新浪微博丨新浪看点丨百度百家丨博客中国丨趣头条丨腾讯云·云+社区

    数据猿
  • docker 实现redis集群搭建

    摘要:接触docker以来,似乎养成了一种习惯,安装什么应用软件都想往docker方向做,今天就想来尝试下使用docker搭建redis集群。

    老梁
  • 漫话:什么是单例模式?

    周末了,临近五一劳动节,女朋友还没有想好要去哪里玩,还在看着各种攻略。我则在旁边一边看书默默的心疼着我的钱包。突然女朋友开始发问:

    乔戈里
  • 阿里3面:Spring声明式事务连环炮,让我措手不及。。

    这篇主要介绍声明式事务的用法,我们在工作中基本上用的都是声明式事务,所以这篇文章是比较重要的,建议各位打起精神,正式开始。

    路人甲Java
  • 如何给女朋友解释什么是单例模式?

    周末了,女朋友还没有想好要去哪里玩,还在看着各种攻略。我则在旁边一边看书默默的心疼着我的钱包。突然女朋友开始发问:

    架构师修行之路
  • UOS系统安装-配置Qt环境

    1、UOS系统相对来说,较为纯净,像GCC、G++等编译器是没有安装的,需要自己去安装

    Sky_Mao

扫码关注云+社区

领取腾讯云代金券