java单例模式教程之java实现单例模式的8大方法
单例模式是Java中常用的设计模式之一。单例模式属于创建型模式,它提供了一种创建对象的最佳方式。
单例模式只创建类的一个对象,之后在一定范围为可任意调用,确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式的几种实现方式
1、懒汉式
懒汉式是一种非线程安全的单例实现方式,实现代码非常容易。
描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
示例代码
public class Singleton {
private static Singleton instance;
private Singleton (){} public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2、懒汉式
懒汉式是一种线程安全的单例实现方式,支持懒加载,实现起来也非常容易。
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
代码示例
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3、饿汉式
饿汉式是一种线程安全的单例实现方式,不支持懒加载,实现起来也非常容易。
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。
代码示例
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
4、双重校验锁
双重校验锁从JDK1.5开始支持,
是一种线程安全的单例实现方式,支持懒加载,实现起来比较复杂。
描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。
代码示例
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
5、静态内部类
静态内部类
是一种线程安全的单例实现方式,支持懒加载,实现难度一般。
描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程,它跟第 3 种方式不同的是:第 3 种方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比第 3 种方式就显得很合理。
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
6、枚举
枚举从JDK1.5开始支持,
是一种线程安全的单例实现方式,不支持懒加载,实现起来比较容易。
描述:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
不能通过 reflection attack 来调用私有构造方法。
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
总结:一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式。
java单例模式教程之java实现单例模式的8大方法的更多相关文章
- Java多线程之Java内存模型
如果要了解Java内存模型,就得对多线程的三大特性有初步的了解. 1.原子性:独一无二.一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行.比如i = i+1:其中就包 ...
- Java入门教程一(Java简介)
什么是Java语言 Java 是由 Sun Microsystems 公司于 1995 年推出的一门面向对象程序设计语言.2010 年 Oracle 公司收购 Sun Microsystems,之后由 ...
- java的nio之:java的nio系列教程之java的io和nio的区别
当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们如何影响您的代 ...
- 2017-07-29 中文代码示例教程之Java编程一天入门
Java编程一天入门 v0.0.1 alpha 共享协议 本作使用署名-非商业使用-禁止演绎协议共享. 前言 Java入门代码用中文写(举例如下)更能被新手理解. 由于至今没有看到类似教程, 在此抛砖 ...
- 我能想到的最浪漫的Java网络教程之Socket,三步到位!!!
简说 如果要使用Java中的TCP/IP通过网络连接到服务器,则需要创建一个java.net.Socket对象以连接到服务器.如果使用JavaNIO,则还可以在JavaNIO中创建SocketChan ...
- Java并发编程之java.util.concurrent包下常见类的使用
一,Condition 一个场景,两个线程数数,同时启动两个线程,线程A数1.2.3,然后线程B数4.5.6,最后线程A数7.8.9,程序结束,这涉及到线程之间的通信. public class Co ...
- web设计经验<九>教你测试手机网页的5大方法
我们知道手机浏览器的使用量每天都在增长,根据StatCounter的统计数据,手机和平板的使用量约占30%的网络流量,这意味着消费者耗费在移动版网页上的时间比以往任何时候都高.可即使具备诸如移动端优先 ...
- Tkinter教程之Event篇(1)'
本文转载自:http://blog.csdn.net/jcodeer/article/details/1823544 ''Tkinter教程之Event篇(1)'''# 事件的使用方法'''1.测试鼠 ...
- Wireshark数据抓包教程之Wireshark捕获数据
Wireshark数据抓包教程之Wireshark捕获数据 Wireshark抓包方法 在使用Wireshark捕获以太网数据,可以捕获分析到自己的数据包,也可以去捕获同一局域网内,在知道对方IP地址 ...
随机推荐
- matplotlib学习记录 二
# 绘制10点到12点的每一分钟气温变化折线图 import random from matplotlib import pyplot as plt # 让matplotlib能够显示中文 plt.r ...
- Python中的属性访问与描述符
Python中的属性访问与描述符 请给作者点赞--> 原文链接 在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象foo,它有一个nam ...
- Mysql主键一致时,可以进行在元数据上的操作
insert into daliy_hit_counter(day,slot,cnt) values(12,12,1) on duplicate key update cnt = cnt +1 dal ...
- py文件转exe时包含paramiko模块出错解决方法
问题描述:python代码中包含paramiko模块的远程登录ssh,在用pyInstaller转为exe时报错, 报错提示为“No handlers could be found for logge ...
- 28、editText只输入英文字母和'-',用于授权码输入
InputFilter filter = new InputFilter() { @Override public CharSequence filter(CharSequence source, i ...
- Collection类及常用API
Collection类及常用API Collection—类集工具类,定义了若干用于类集和映射的算法,这些算法被定义为静态方法,具体查看api文档; a) public static void so ...
- C/C++、Java、Python谁是编译型语言,谁是解释型语言?
最近各大互联网公司线上笔试,编程题目里的编译器只支持C/C++.Java,甚至有的支持javaScrpit和Pascal,就是不支持Python.让一直以来用惯了Python的我直吐血,于是今天痛定思 ...
- 【Luogu】P2221高速公路(线段树乱搞)
题目链接 这题……我从一开始就想歪了qwq. 为了缅怀逝去的一小时我就把我的30分暴力思路放上来. 首先我们观察枚举的区间.假设我们要枚举的范围是1~5之间的四条路,为了方便我们把它们叫做abcd. ...
- Python基础教程总结(一)
引言: 一直都听说Python很强大,以前只是浏览了一些博客,发现有点像数学建模时使用的Matlab,就没有深入去了解了.如今Python使用的地方越来越多,最近又在学习机器学习方面的知识,因此想系统 ...
- scrapy之Pipeline
官方文档:https://docs.scrapy.org/en/latest/topics/item-pipeline.html 激活pipeline,需要在settings里配置,然而这里配置的pi ...