Java公开课-06.单例
一. 什么是单例模式
因程序需要,有时我们只需要某个类同时保留一个对象,不希望有更多对象,此时,我们则应考虑单例模式的设计。
二. 单例模式的特点
1. 单例模式只能有一个实例。
2. 单例类必须创建自己的唯一实例。
3. 单例类必须向其他对象提供这一实例。
三. 单例模式VS静态类
在知道了什么是单例模式后,我想你一定会想到静态类,“既然只使用一个对象,为何不干脆使用静态类?”,这里我会将单例模式和静态类进行一个比较。
1. 单例可以继承和被继承,方法可以被override,而静态方法不可以。
2. 静态方法中产生的对象会在执行后被释放,进而被GC清理,不会一直存在于内存中。
3. 静态类会在第一次运行时初始化,单例模式可以有其他的选择,即可以延迟加载。
4. 基于2, 3条,由于单例对象往往存在于DAO层(例如sessionFactory),如果反复的初始化和释放,则会占用很多资源,而使用单例模式将其常驻于内存可以更加节约资源。
5. 静态方法有更高的访问效率。
6. 单例模式很容易被测试。
几个关于静态类的误解:
误解一:静态方法常驻内存而实例方法不是。
实际上,特殊编写的实例方法可以常驻内存,而静态方法需要不断初始化和释放。
误解二:静态方法在堆(heap)上,实例方法在栈(stack)上。
实际上,都是加载到特殊的不可写的代码内存区域中。
静态类和单例模式情景的选择:
情景一:不需要维持任何状态,仅仅用于全局访问,此时更适合使用静态类。
情景二:需要维持一些特定的状态,此时更适合使用单例模式。
四. 单例模式的实现
1. 懒汉模式

public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){ }
public static SingletonDemo getInstance(){
if(instance==null){
instance=new SingletonDemo();
}
return instance;
}
}

如上,通过提供一个静态的对象instance,利用private权限的构造方法和getInstance()方法来给予访问者一个单例。
缺点是,没有考虑到线程安全,可能存在多个访问者同时访问,并同时构造了多个对象的问题。之所以叫做懒汉模式,主要是因为此种方法可以非常明显的lazy loading。
针对懒汉模式线程不安全的问题,我们自然想到了,在getInstance()方法前加锁,于是就有了第二种实现。
2. 线程安全的懒汉模式

public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){ }
public static synchronized SingletonDemo getInstance(){
if(instance==null){
instance=new SingletonDemo();
}
return instance;
}
}

然而并发其实是一种特殊情况,大多时候这个锁占用的额外资源都浪费了,这种打补丁方式写出来的结构效率很低。
3. 饿汉模式

public class SingletonDemo {
private static SingletonDemo instance=new SingletonDemo();
private SingletonDemo(){ }
public static SingletonDemo getInstance(){
return instance;
}
}

直接在运行这个类的时候进行一次loading,之后直接访问。显然,这种方法没有起到lazy loading的效果,考虑到前面提到的和静态类的对比,这种方法只比静态类多了一个内存常驻而已。
4. 静态类内部加载

public class SingletonDemo {
private static class SingletonHolder{
private static SingletonDemo instance=new SingletonDemo();
}
private SingletonDemo(){
System.out.println("Singleton has loaded");
}
public static SingletonDemo getInstance(){
return SingletonHolder.instance;
}
}

使用内部类的好处是,静态内部类不会在单例加载时就加载,而是在调用getInstance()方法时才进行加载,达到了类似懒汉模式的效果,而这种方法又是线程安全的。
5. 枚举方法
enum SingletonDemo{
INSTANCE;
public void otherMethods(){
System.out.println("Something");
}
}
Effective Java作者Josh Bloch 提倡的方式,在我看来简直是来自神的写法。解决了以下三个问题:
(1)自由序列化。
(2)保证只有一个实例。
(3)线程安全。
如果我们想调用它的方法时,仅需要以下操作:
public class Hello {
public static void main(String[] args){
SingletonDemo.INSTANCE.otherMethods();
}
}
这种充满美感的代码真的已经终结了其他一切实现方法了。
6. 双重校验锁法

public class SingletonDemo {
private volatile static SingletonDemo instance;
private SingletonDemo(){
System.out.println("Singleton has loaded");
}
public static SingletonDemo getInstance(){
if(instance==null){
synchronized (SingletonDemo.class){
if(instance==null){
instance=new SingletonDemo();
}
}
}
return instance;
}
}

接下来我解释一下在并发时,双重校验锁法会有怎样的情景:
STEP 1. 线程A访问getInstance()方法,因为单例还没有实例化,所以进入了锁定块。
STEP 2. 线程B访问getInstance()方法,因为单例还没有实例化,得以访问接下来代码块,而接下来代码块已经被线程1锁定。
STEP 3. 线程A进入下一判断,因为单例还没有实例化,所以进行单例实例化,成功实例化后退出代码块,解除锁定。
STEP 4. 线程B进入接下来代码块,锁定线程,进入下一判断,因为已经实例化,退出代码块,解除锁定。
STEP 5. 线程A获取到了单例实例并返回,线程B没有获取到单例并返回Null。
理论上双重校验锁法是线程安全的,并且,这种方法实现了lazyloading。
Java公开课-06.单例的更多相关文章
- 学习经验分享(最近听了一节Java公开课)
最近听了一节Java公开课,讲的Tomcat8.0的,老师分享的学习方法很好, 时间和精力要用对地方 1.学习一个知识的广度和深度,先学主要的主流的,不要学了很多不该学,没必要学的东西 2.要花时间总 ...
- Java学习笔记之---单例模型
Java学习笔记之---单例模型 单例模型分为:饿汉式,懒汉式 (一)要点 1.某个类只能有一个实例 2.必须自行创建实例 3.必须自行向整个系统提供这个实例 (二)实现 1.只提供私有的构造方法 2 ...
- java中安全的单例与不安全的单例
java中安全的单例与不安全的单例 1.内部静态类(安全的) public class Singleton { private static class SingletonHolder{ privat ...
- JAVA的设计模式之单例设计模式
1.确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例. 1)理论 Java Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 使用Singl ...
- java基础学习之单例设计模式学习
最近狂补java基础的我重新学习了下单例,下面直接贴出代码,以作备忘 package com.darling.single; /** * 单例模式 * 单例即在内存中只存在该类的一个实例,要想实现这个 ...
- 【java设计模式】之 单例(Singleton)模式
1. 单例模式的定义 单例模式(Singleton Pattern)是一个比較简单的模式.其原始定义例如以下:Ensure a class has only one instance, and pro ...
- Java设计模式:Singleton(单例)模式
概念定义 Singleton(单例)模式是指在程序运行期间, 某些类只实例化一次,创建一个全局唯一对象.因此,单例类只能有一个实例,且必须自己创建自己的这个唯一实例,并对外提供访问该实例的方式. 单例 ...
- Java中Class和单例类的作用与类成员的理解
Java中Class类的作用与深入理解 在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识.这个信息跟踪着每个对象所属的类.JVM利用运行时信息选择相应的方法执行.而保存 ...
- java新手笔记12 单例
1.单例 package com.yfs.javase; public class Singleton { //private static final Singleton single = new ...
随机推荐
- Cocos2D的OALSimpleAudio预加载音频
在OALSimpleAudio接口中,没有委托机制和通知机制告诉你什么时候预加载完成.也不需要这样的机制. 如下代码: //Listing 11-1. Preloading a background ...
- 单向循环链表C语言实现
我们都知道,单向链表最后指向为NULL,也就是为空,那单向循环链表就是不指向为NULL了,指向头节点,所以下面这个程序运行结果就是,你将会看到遍历链表的时候就是一个死循环,因为它不指向为NULL,也是 ...
- Palette状态栏颜色提取,写的不错就分享了
Palette 说Palette之前先说下前面提到的Pager.ViewPager是什么大家应该都是知道的了,一般ViewPager.xxxTabStrip.Fragment三个好基友是一起出现的.这 ...
- Java-ServletContextEvent-ServletContextAttributeEvent
//这是一个事件类用来通知一个web 应用的servlet 上下文的改变 public class ServletContextEvent extends java.util.EventObject ...
- 求剁手的分享,如何简单开发js图表
前段时间做的一个项目里需要用到js图表,在网上找了下,大概找到了highcharts.fusioncharts这些国外产品. 因为都收费,虽然有盗版,我也不敢用,万一被找上们来就砸锅卖铁了要.自己写j ...
- objc写一个NSMutableArray不连续索引替换对象的方法
NSMutableArray内置的方法-(void)replaceObjectsAtIndexes:(NSIndexSet*)set withObjects:(NSArray*)objs 只能替换一段 ...
- Spring 学习笔记 Bean的作用域
在配置文件中定义Bean时,用户不但可以配置Bean的属性值以及相互之间的依赖关系,还可以定义Bean的作用域.作用域将对Bean的生命周期和创建方式产生影响.在低版本的Spring中,仅有两个作用域 ...
- permutations II(全排列 2)
题目要求 Given a collection of numbers that might contain duplicates, return all possible unique permuta ...
- 第8章-Java集合 --- 概述
第8章-Java集合 --- 概述 (1)Java集合类是一种特别有用的工具类,可以用于存储数量不等的多个对象,并可以实现常用的数据结构,如 栈.队列等. (2)Java集合大致可分为Set.List ...
- 兼容 Android 4.4 透明状态栏与导航栏
http://www.apkbus.com/Android-163388-1-1.html?_dsign=73d41229 android 系统自4.2 开始 UI 上就没多大改变,4.4 也只是增加 ...