9种Java单例模式详解
单例模式的特点
- 一个类只允许产生一个实例化对象。
- 单例类构造方法私有化,不允许外部创建对象。
- 单例类向外提供静态方法,调用方法返回内部创建的实例化对象。
懒汉式(线程不安全)
其主要表现在单例类在外部需要创建实例化对象时再进行实例化,进而达到Lazy Loading 的效果。
通过静态方法 getSingleton() 和private 权限构造方法为创建一个实例化对象提供唯一的途径。
不足:未考虑到多线程的情况下可能会存在多个访问者同时访问,发生构造出多个对象的问题,所以在多线程下不可用这种方法。
/**
* @author MrRoot
* @since 2018-12-17
* 懒汉式(线程不安全)
*/
public class Singleton {
private static Singleton singleton; private Singleton(){ } public static Singleton singleton(){
if (singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
懒汉式(线程安全,同步方法,不推荐使用)
针对懒汉式的线程不安全,自然会想到给 getSingleton() 进行 synchronized 加锁来保证线程同步。
不足:效率低。大多数情况下这个锁占用的额外资源都浪费了,每个线程在想获得类的实例时候,执行 getSingleton() 方法都要进行同步。
/**
* @author MrRoot
* @since 2019-3-27
* 懒汉式(线程安全,同步方法,不推荐使用)
*/
public class Singleton {
private static Singleton singleton; private Singleton(){ } public static synchronized Singleton singleton(){
if (singleton == null){
singleton = new Singleton();
}
return singleton;
} }
饿汉式(线程安全)
在进行类加载时完成实例化对象的过程就是饿汉式的形式。
避免了线程同步问题,在运行这个类的时候进行加载,之后直接访问
不足:相比接下来的静态内部类而言,这种方法比静态内部类多了内存常驻,容易造成内存浪费,也未达到延迟加载的效果。
/**
* @author MrRoot
* @since 2019-3-27
* 饿汉式(线程安全)
*/
public class Singleton{
private static Singleton singleton = new Singleton(); private Singleton(){ } public static Singleton singleton(){
return singleton;
}
}
静态内部类加载(线程安全)
静态内部类不会在单例加载时加载,当调用 getSingleton() 方法时才会进行加载,达到类似懒汉式效果,并且也是线程安全的。
类的静态属性只会在第一次加载类时进行初始化,所以上面的方法JVM 帮助我们保证了线程的安全性,在类进行初始化时,其他线程无法进入。
/**
* @author MrRoot
* @since 2019-3-27
* 静态内部类加载(线程安全)
*/
public class Singleton{
private static Singleton singleton; private static class SingletonInner{
private static final Singleton instance = new Singleton();
} public static Singleton getSingleton(){
return SingletonInner.instance;
}
}
枚举(线程安全)
自由串行化;保证只有一个实例;线程安全。
Effective Java 作者所提倡的方法,近乎完美,在继承场景下不适用。
/**
* @author MrRoot
* @since 2019-3-27
* 枚举(线程安全)
*/
enum Singleton{
INSTANCE; public void method(){ }
} class Test{
public static void main(String[] args) {
Singleton.INSTANCE.method();
}
}
懒汉式双重校验锁法(通常线程安全,不可保证完全安全)
使用同步代码块避免了第二种方法的效率低的问题,但此方法并不能完全起到线程同步的作用,与上面第一种方法产生的问题相似,多线程访问时可能产生多个对象。
/**
* @author MrRoot
* @since 2019-3-27
* 懒汉式双重校验锁法(通常线程安全,不可保证完全安全)
*/
class Singleton{
private static Singleton singleton; private Singleton(){ } public static Singleton singleton(){
if (singleton == null){
synchronized (Singleton.class){
if (singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
懒汉式双重检查终极版
与第六种方法不同的是,此方法给singleton 的声明上加了关键字 volatile ,进而解决了低概率的线程不安全问题。
volatile 起到禁止指令重排的作用,在它赋值完成之前,就不会调用读操作(singleton == null)。
/**
* @author MrRoot
* @since 2019-3-27
* 懒汉式双重检查终极版(volatile)
*/
class Singleton{
private static volatile Singleton singleton; private Singleton(){ } public static Singleton singleton(){
if (singleton == null){
synchronized (Singleton.class){
if (singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
使用 ThreadLocal 实现(线程安全)
ThreadLocal 会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。
对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal 采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
/**
* @author MrRoot
* @since 2019-3-27
* 使用 ThreadLocal 实现(线程安全)
*/
class Singleton{
private static final ThreadLocal<Singleton> singleton = new
ThreadLocal<Singleton>(){
@Override
protected Singleton initialValue(){
return new Singleton();
}
}; private Singleton(){ } public static Singleton getSingleton(){
return singleton.get();
}
}
使用CAS 锁实现(线程安全)
/**
* @author MrRoot
* @since 2019-3-27
* 使用 CAS 实现(线程安全)
*/
public class Singleton {
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>(); private Singleton(){ } public static final Singleton getSingleton(){
for (;;){
Singleton current = INSTANCE.get();
if (current != null){
return current;
}
current = new Singleton();
if (INSTANCE.compareAndSet(null,current)){
return current;
}
}
} public static void main(String[] args) {
Singleton singleton1 = Singleton.getSingleton();
Singleton singleton2 = Singleton.getSingleton();
System.out.println(singleton1 == singleton2);
}
}
9种Java单例模式详解的更多相关文章
- 9种Java单例模式详解(推荐)
单例模式的特点 一个类只允许产生一个实例化对象. 单例类构造方法私有化,不允许外部创建对象. 单例类向外提供静态方法,调用方法返回内部创建的实例化对象. 懒汉式(线程不安全) 其主要表现在单例类在外 ...
- Java 单例模式详解
概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. ...
- 【JAVA单例模式详解】
设计模式是一种思想,适合于任何一门面向对象的语言.共有23种设计模式. 单例设计模式所解决的问题就是:保证类的对象在内存中唯一. 举例: A.B类都想要操作配置文件信息Config.java,所以在方 ...
- Java 单例模式详解(转)
概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. ...
- java单例模式详解
饿汉法 饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建.代码如下: public class Singleton { private static Singleton = ne ...
- android java 设计模式详解 Demo
android java 设计模式详解 最近看了一篇设计模式的文章,深得体会,在此基础我将每种设计模式的案例都写成Demo的形式,方便读者研究学习, 首先先将文章分享给大家: 设计模式(Design ...
- Java内部类详解
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
- Java虚拟机详解----JVM常见问题总结
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- [转] Java内部类详解
作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...
随机推荐
- 算法训练 最大的算式(DP)
问题描述 题目很简单,给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大.因为乘号和加号一共就是N-1个了,所以恰好每两个相邻数字之间都有一个符号 ...
- LINQ和Lambda表达式
前言 前段时间接触了一种新的表达式,但是不知道这个是什么意思,所以就先站在巨人的肩膀用了,现在听师哥说这种写法是Lambda表达式.我一直以为,这个Lambda表达式和LINQ查询有异曲同工之妙,可惜 ...
- 形态形成场(矩阵乘法优化dp)
形态形成场(矩阵乘法优化dp) 短信中将会涉及前\(k\)种大写字母,每个大写字母都有一个对应的替换式\(Si\),替换式中只会出现大写字母和数字,比如\(A→BB,B→CC0,C→123\),代表 ...
- css 选择器;盒模型
一.引入方式:(1)CSS 层叠样式表 作用:修饰网页结构 (2)css的三种引入方式 - 行内样式 注意:行内样式的优先级是最高的 - 内接样式 - 外接样式 二.css选择器 基础选择器 * 通配 ...
- Python——用os模块寻找指定目录(包括子目录)下所有图片文件
import os # 导入os模块 def search_file(start_dir): img_list = [] extend_name = ['.jpg', '.png', '.gif'] ...
- Python 模拟简单区块链
首先这是说明一下这是Tiny熊老师的教程https://www.cnblogs.com/tinyxiong 另外还要说明一下,暑假指导老师让我们做一些关于区块链的应用.这里只是涉及极其简单的模拟,主要 ...
- 「杂录」CQOI 2018 背板记
背景 经过一天天的等待,终于迎来了\(CQOI2018\),想想\(NOIp\)过后到现在,已经有了快要半年了,曾经遥遥无期,没想到时间一转眼就过去了-- 日志 \(Day0\) 因为明天就要考试了, ...
- [SCOI2010]序列操作 BZOJ1858 线段树
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...
- Infiniband交换机的FabricMonitor加载数据hang
刚刚帮客户将Exadata中Infiniband交换机的固件版本从2.1.3-1 升级到2.2.7-1,但升级后发现Infiniband交换机的FabricMonitor功能无法使用,具体如下图所示. ...
- Avito Cool Challenge 2018:D. Maximum Distance
D. Maximum Distance 题目链接:https://codeforces.com/contest/1081/problem/D 题意: 给出一个连通图以及一些特殊点,现在定义cost(u ...