单件模式(单例模式)
来源:互联网 发布:单片机实现呼吸灯 编辑:程序博客网 时间:2024/05/16 02:12
【0】README
0.1)本文部分描述转自 “head first 设计模式”, 旨在学习 单件模式(单例模式) 的相关知识 及其应用;
【1】单件模式
1.0)单件模式的应用背景:有一些对象其实我们只需要一个,比方说: 线程池,缓存,对话框,注册表等的对象,这都可以通过单件模式来解决;
1.1)定义:确保一个类只有一个实例,并提供一个全局访问点;
1.2)全局变量的缺点:如果将对象赋值给一个全局变量,那么你必须在程序一开始就创建好对象,对吧?万一这个对象非常耗费资源,而程序在这次的执行过程中又一直没有用到它,不就形成浪费了嘛?(干货——使用全局变量可能出现的问题)
【2】剖析经典的单件模式实现
public class Singleton {private static Singleton uniqueInstance; private Singleton() {}public static Singleton getInstance() {if (uniqueInstance == null) {uniqueInstance = new Singleton();}return uniqueInstance;} // other useful methods herepublic String getDescription() {return "I'm a classic Singleton!";}}
对以上的代码的分析(Analysis):
A1)如果该对象不存在,我们就利用私有构造器产生一个 Singleton 实例并把它赋值到 uniqueInstance 静态变量中。A2)注意:如果我们不需要这个实例,它就永远不会产生。这就是“延迟实例化”;(干货——延迟实例化)A3)看看它的类图: getInstance()方法是静态的,这意味着它是一个类方法,所以可以在代码的任何地方使用 Singleton.getInstance() 访问它。这和访问全局变量一样简单,只是多了一个优点: 单件可以延迟实例化;
【3】并发访问实例方法(处理多线程)
3.0)多线程访问实例方法所遇到的问题:返回了两个不同对象object1 和 object2,多线程访问的细粒度steps 如下所示:
3.1)把 getInstance() 变成同步(synchronized)方法,解决并发问题;
public class ConcurrencySingleton {private static ConcurrencySingleton uniqueInstance; private ConcurrencySingleton() {} public static synchronized ConcurrencySingleton getInstance() {if (uniqueInstance == null) {uniqueInstance = new ConcurrencySingleton();}return uniqueInstance;} // other useful methods herepublic String getDescription() {return "I'm a classic Singleton!";}}
3.2)加上 synchronized后的性能问题:显然,这样会降低同步的性能,这引入了另一个问题;
问题详述:这个问题比你想象的还要严重,因为只有第一次执行此方法时,才真正需要同步。换句话说,一旦设置好uniqueInstanc 变量, 就不再需要同步这个方法了。之后每次调用这个方法,同步都是一种累赘,显著地降低了程序性能;(因为当多个线程并发访问 getInstance 方法的时候,有且只有一个线程能够获得同步锁,访问方法成功,某个线程访问成功后,其他线程才有可能去访问该方法,此时叫串行访问而不是并行访问了);
3.3)solution(多线程下的单件模式):
s1)如果getInstance() 的性能对应用程序不是很关键,就什么也别做;(不用加 synchronized关键字);s2)使用 急切创建实例,而不用延迟实例化的做法;(干货——比较急切实例化和延迟实例化的区别)public class Singleton {private static Singleton uniqueInstance = new Singleton(); private Singleton() {}public static Singleton getInstance() {return uniqueInstance;}s3)使用双重检查加锁,在 getInstance()中减少使用同步:利用双重检查加锁,首先检查是否实例对象已经创建了,如果没有创建,才进行同步。这样一来,也就只有第一次才会同步,这正是我们想要的;(干货——我个人推荐使用这个加锁机制)public class ConcurrencySingletonV2 {private volatile static ConcurrencySingletonV2 uniqueInstance; private ConcurrencySingletonV2() {} // 只有第一次才执行全部代码,否则跳转到 return 语句行public static ConcurrencySingletonV2 getInstance() {if (uniqueInstance == null) { // 第一次检查 synchronized (ConcurrencySingletonV2.class) {if (uniqueInstance == null) { // 第二次检查:进入同步块后,如果实例仍然是null,才创建实例uniqueInstance = new ConcurrencySingletonV2();}}}return uniqueInstance;}}Attention)Volatile 关键字:为实例域的同步访问提供了一种免锁机制, 如果说明一个域为 volatile, 那么编译器和 虚拟机就知道该域是可能被另一个线程并发更新的;
0 0
- 单件模式(单例模式)
- 浅谈单件模式(单例模式--Singleton Pattern)
- 浅析设计模式之单例模式(又名:单值模式、单件模式)
- Singleton(单件)模式
- 单件模式(1)
- 单件模式(c++)
- 单件模式(Singleton)
- 单件模式(Singleton)
- 单件模式(java)
- 设计模式--单件模式(Singleton)
- 学习模式----单件模式(1)
- 单件模式(创建型模式)
- 设计模式(一)单件模式
- 单件模式
- 单件模式
- 设计模式-单件
- singleton单件模式
- Singleton (单件模式)
- Spring 中如何向 Bean 注入系统属性或环境变量
- Nginx在Window下的使用笔记
- Linux-非结构化数据同步-Linux下实现非结构化数据同步的介绍1
- object类
- 前台删除多行记录,并传递到后台
- 单件模式(单例模式)
- ORACLE多表关联UPDATE 语句
- 在Ubuntu 14.04.1中安装VMware Tools的步骤
- 自定义下拉刷新上拉加载动画
- openstack里的mysql数据库
- 获取程序的版本号
- java servlet 技术
- 如何实现ZBrush中部分模型的选择和隐藏
- C++stringstream的clear()清空误区