单例模式总结(Java版)
1:懒汉的设计模式,在第一次调用的时候才完成相关的初始化操作
懒汉式是典型的时间换空间,就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间
package com.xiaohao.test;
/**
* 使用懒汉模式创建一个单例模式
* @author lenovo
*
*/
public class Singleton {
private static Singleton instance=null;
/**
* 返回或者创建相关的单例实例
* @return
*/
public static synchronized Singleton getInstance(){//使用同步方法保证线程安全
if(instance==null){
instance=new Singleton();
}
return instance;
}
/**
* 一个私有的构造方法,使外部的对象不能new相关的实例,这个尤其要注意,一定要提供默认的私有化的方法去覆盖默认的构造方法
* 否则的话,如果用户直接去new一个对象的话,就无法保证单例了~~~
*/
private Singleton(){}
}
2:饿汉的设计模式,在初始化类的过程中就会完成相关实例的初始化,一般认为这种方式要更加安全些
饿汉式是典型的空间换时间,当类装载的时候就会创建类的实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断,节省了运行时间。
package com.xiaohao.test;
/**
* 使用饿汉模式创建一个单例 模式
* @author lenovo
*
*/
public class Singleton {
//这个内部的单例仅仅用于内部访问,在初始化相关类的时候,就完成了相关单例类的初始化
//同时使用final修饰符修饰,一旦初始化值之后,不允许修改相关的值,这样也就实现了系统中的唯一
private static final Singleton instance=new Singleton();
/**
* 返回或者创建相关的单例实例
* @return
*/
public static Singleton getInstance(){
return instance;
}
/**
* 一个私有的构造方法,使外部的对象不能new相关的实例,这个尤其要注意,一定要提供默认的私有化的方法去覆盖默认的构造方法
* 否则的话,如果用户直接去new一个对象的话,就无法保证单例了~~~
*/
private Singleton(){}
}
此外还有一个比较给力的实现单例的方式,推荐大家使用这种方式:
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
*/
static class SingletonHolder {
/**
* 静态初始化器,由JVM来保证线程安全
*/
static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
在加载singleton时并不加载它的内部类SingletonHolder,而在调用getInstance()时调用SingletonHolder时才加载SingletonHolder,从而调用singleton的构造函数,实例化singleton,从而达到lazy loading的效果。
3:双重锁的设计模式,实现在多线程下,相关性能的提高,尤其避免懒汉模式中,每次获取实例的时候都需要线程同步的问题
双重锁的主要目的是解决每次获取实例的时候都需要进行线程等待,只有在第一次实例化时,才启用同步机制,提高了性能。
提示:由于volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高。因此一般建议,没有特别的需要,不要使用。也就是说,虽然可以使用“双重检 查加锁”机制来实现线程安全的单例,但并不建议大量采用,可以根据情况来选用。
package com.xiaohao.test;
/**
* 使用双重锁模式创建一个单例模式
* @author lenovo
*
*/
public class Singleton {
private static Singleton instance=null;
/**
* 返回或者创建相关的单例实例
* @return
*/
public static Singleton getInstance(){
if(instance==null)
{
synchronized (Singleton.class){//需要注意的是,这里锁住的是类,一旦加上这个类锁之后,所有和这个类相关的操作(包括这个类的所有属性和方法)都需要进行相关的等待
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
/**
* 一个私有的构造方法,使外部的对象不能new相关的实例,这个尤其要注意,一定要提供默认的私有化的方法去覆盖默认的构造方法
* 否则的话,如果用户直接去new一个对象的话,就无法保证单例了~~~
*/
private Singleton(){}
}
}
这个方法表面上看起来很完美,你只需要付出一次同步块的开销,但它依然有问题。除非你声明instance
变量时使用了volatile关键字。没有volatile
修饰符,可能出现Java中的另一个线程看到个初始化了一半的instance
的情况,但使用了volatile
变量后,就能保证先行发生关系(happens-before relationship)。对于volatile
变量_instance
,所有的写(write)都将先行发生于读(read),在Java 5之前不是这样,所以在这之前使用双重检查锁有问题。现在,有了先行发生的保障(happens-before guarantee),你可以安全地假设其会工作良好。另外,这不是创建线程安全的单例模式的最好方法,你可以使用枚举实现单例模式,这种方法在实例创建时提供了内置的线程安全。另一种方法是使用静态持有者模式(static holder pattern),这种方式就是开始的饿汉模式,所以说饿汉模式相对来说比较安全一些。
package com.xiaohao.test;
/**
* 使用双重锁模式创建一个单例模式,双重锁模式下的进一步优化
* @author lenovo
*
*/
public class Singleton {
//注意这里面的volatile 这个关键字,它的主要作用是写(write)优于读(read),前提是jdk的版本要不低于jdk5.0
private volatile static Singleton instance=null;
/**
* 返回或者创建相关的单例实例
* @return
*/
public static Singleton getInstance(){
if(instance==null)
{
synchronized (Singleton.class){//需要注意的是,这里锁住的是类,一旦加上这个类锁之后,所有和这个类相关的操作(包括这个类的所有属性和方法)都需要进行相关的等待
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
/**
* 一个私有的构造方法,使外部的对象不能new相关的实例,这个尤其要注意,一定要提供默认的私有化的方法去覆盖默认的构造方法
* 否则的话,如果用户直接去new一个对象的话,就无法保证单例了~~~
*/
private Singleton(){}
}
4:使用枚举实现单例模式,这种方法在实例创建时提供了内置的线程安全
package com.xiaohao.test;
/**
* 使枚举的方法创建一个单例类
* @author lenovo
*
*/
public enum Singleton {
INSTANCE;// 使用枚举类的方法创建一个单例,据说这是目前位置,无论是多线程还是,防止反射创建
//相关对象最有用的方法,推荐使用
}
单元素的枚举类型已经成为实现Singleton的最佳方法。用枚举来实现单例非常简单,只需要编写一个包含单个元素的枚举类型即可。使用enum关键字来实现单例模式的好处是这样非常简洁,并且无偿地提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。使用枚举来实现单实例控制会更加简洁,而且无偿地提供了序列化机制,并由JVM从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式。——来自《Effective Java》
***知识补充(拷贝的)----针对谷歌那个工程师的方法:
这个模式综合使用了Java的类级内部类和多线程缺省同步锁的知识,很巧妙地同时实现了延迟加载和线程安全。
1.相应的基础知识
- 什么是类级内部类?
简单点说,类级内部类指的是,有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类。
类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。
类级内部类中,可以定义静态的方法。在静态方法中只能够引用外部类中的静态成员方法或者成员变量。
类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载。
- 多线程缺省同步锁的知识
大家都知道,在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制。但是在某些情况中,JVM已经隐含地为您执行了同步,这些情况下就不用自己再来进行同步控制了。这些情况包括:
1.由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时
2.访问final字段时
3.在创建线程之前创建对象时
4.线程可以看见它将要处理的对象时
2.解决方案的思路
要想很简单地实现线程安全,可以采用静态初始化器的方式,它可以由JVM来保证线程的安全性。比如前面的饿汉式实现方式。但是这样一来,不是会浪费一定的空间吗?因为这种实现方式,会在类装载的时候就初始化对象,不管你需不需要。
如果现在有一种方法能够让类装载的时候不去初始化对象,那不就解决问题了?一种可行的方式就是采用类级内部类,在这个类级内部类里面去创建对象实例。这样一来,只要
不使用到这个类级内部类,那就不会创建对象实例,从而同时实现延迟加载和线程安全。
****最后需要注意一点,上面除了使用枚举类的方法外,其它的方法都可以通过java的反射机制创建相关的对象,即使使用private 重写了相关的构造方法~~
单例模式总结(Java版)的更多相关文章
- 你真的会写单例模式吗-------Java实现
转载: 你真的会写单例模式吗--Java实现 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模式,还真得费一番脑筋.本文对Java中常见的单例模式写法做了一个总结,如有错漏 ...
- 网页爬虫的设计与实现(Java版)
网页爬虫的设计与实现(Java版) 最近为了练手而且对网页爬虫也挺感兴趣,决定自己写一个网页爬虫程序. 首先看看爬虫都应该有哪些功能. 内容来自(http://www.ibm.com/deve ...
- [转] 你真的会写单例模式吗——Java实现
你真的会写单例模式吗——Java实现 原文:http://www.tuicool.com/articles/MBrUfy6 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模 ...
- pureMVC java版搭建流程
转自:http://blog.csdn.net/sutaizi/article/details/6588004 pureMVC 是一个轻量级的框架 它在 flex中非常流行(和cairngorm差不多 ...
- ArcGIS Server 10 Java 版的Rest服务手动配置方法
Java版的Manager中发布的服务默认只发布了该服务的SOAP接口,而REST接口需要用户在信息服务器,如Tomcat. Apache.WebLogic等中手工配置.由于在Java版的Server ...
- PetaPojo —— JAVA版的PetaPoco
背景 由于工作的一些原因,需要从C#转成JAVA.之前PetaPoco用得真是非常舒服,在学习JAVA的过程中熟悉了一下JAVA的数据组件: MyBatis 非常流行,代码生成也很成熟,性能也很好.但 ...
- 【转载】java版打字练习软件
网上找到一个java版的打字的游戏 import java.applet.Applet; import java.applet.AudioClip; import java.awt.Dimension ...
- 微博地址url(id)与mid的相互转换 Java版
原理: 新浪微博的URL都是如:http://weibo.com/2480531040/z8ElgBLeQ这样三部分. 第一部分(绿色部分)为新浪微博的域名,第二部分(红色部分)为博主Uid,第三部分 ...
- JCEF3——谷歌浏览器内核Java版实现(一):使用jawt获取窗体句柄
前言 最近一段时间研究谷歌浏览器内核.谷歌浏览器内核一直开源,并维护更新,它的开源项目中内核更新速度和Chrome浏览器版本更新进度一样!而且它不同于WebKit(值得一题的是谷歌浏览器已不使用Web ...
- Selenium关键字驱动测试框架Demo(Java版)
Selenium关键字驱动测试框架Demo(Java版)http://www.docin.com/p-803493675.html
随机推荐
- SpringMVC——实现拦截器
1. SpringMVC拦截器的概念与Struts2相同 2. 实现拦截器 (1) 项目结构 (2) 实现HandlerInterceptor接口 package com.zhengbin.contr ...
- 项目管理工具:Maven使用方法总结
阅读目录 一.概念 二.Maven安装 三.常用命令 四.生命周期 五.第一个Maven项目 六.POM文件 七.Maven库 八.参考资料 回到顶部 一.概念 Maven是一个项目管理和构建自动化工 ...
- 1048 图的宽度优先遍历序列 c语言
描述 图(graph)是数据结构 G=(V,E),其中V是G中结点的有限非空集合,结点的偶对称为边(edge):E是G中边的有限集合.设V={0,1,2,……,n-1},图中的结点又称为顶点(vert ...
- 3. 使用绘图API自定义视图 --- 旋转的方块
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; impor ...
- 【LeetCode 213】House Robber II
This is an extension of House Robber. After robbing those houses on that street, the thief has found ...
- IAR编译信息分析
1.怎么设置可以查看单片的内存(消耗)使用状况? IAR的菜单栏 -->Tools -->IDE Options -->Messages -->Show build messa ...
- 用Vmware安装centos5
Vmware安装过程就不详述了,这里从创建虚拟机开始记录. 选择创建虚拟机 下一步 选择稍后安装 选择安装的操作系统版本,需要说明的是,CentOs 5 就是RHEL 5 设置虚拟机名称及虚拟机位置 ...
- 【转载】cocos2d-x教程 Mac系统下搭建Lua的编码环境
原文链接:http://blog.csdn.net/u012945598/article/details/17168831 在使用Lua写脚本的时候大家都会因为没有代码提示导致敲代码的效率有所下降 ...
- 看仪表盘——validation
先试想一下,对于一个简单的二分类问题,我们如何选择合适的算法? 我们有许许多多的H,如何选择出最为合适的算法? 最合理的方法是:对于每一个H,我们选择出Eout最小的g,然后对于各个g,再选择Eout ...
- bzoj 1109 [POI2007]堆积木Klo(LIS)
[题意] n个数的序列,删除一个数后序列左移,求最后满足i==a[i]的最大个数. [思路] 设最终得到a[i]==i的序列为s,则s应满足: i<j,a[i]<a[j],i-a[i]&l ...