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/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...
随机推荐
- POJ - 2528Mayor's posters (离散化+线段树区间覆盖)
The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign h ...
- Codeforces Round #521 (Div. 3) C. Good Array
C. Good Array time limit per test 1 second memory limit per test 256 megabytes input standard input ...
- Exadata LVM snapshot备份失败
一台X4-2 的计算节点进行image升级,在正式升级之前利用LVM snapshot备份操作系统时备份失败,并且报大量IO错误,提示无法找到LVM snapshot的挂载点.检查文件系统状态: [r ...
- jquery知识点结合使用
1.在页面的某个具有id的element内插入其他element,并给其增加悬浮提示. $('#id').after('<div id='box'></div>'); $('# ...
- HDU计算机学院大学生程序设计竞赛(2015’12)Happy Value
Problem Description In an apartment, there are N residents. The Internet Service Provider (ISP) want ...
- Oracle table-lock的5种模式
Oracle中的锁定可以分为几类: 1.DML lock(data lock), 2.DDL lock(dictionary lock) 3.internal lock/latch. DML lock ...
- mgo01_window server 2012上安装mongo4.0
目前mongo最新版为4.0(2018-07-18),下载地址 https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-4 ...
- linux 6 查看防火墙状态及开启关闭命令
linux 6 查看防火墙状态及开启关闭命令 https://blog.csdn.net/lv_shijun/article/details/52453882 存在以下两种方式: 一.service方 ...
- Vue在单独引入js文件中使用ElementUI的组件
Vue在单独引入js文件中使用ElementUI的组件 问题场景: 我想在vue中的js文件中使用elementUI中的组件,因为我在main.js中引入了element包和它的css,并挂载到了全局 ...
- docker+ bind mount 部署复杂flask应用
报错如下: [root@test-wenqiang flask-skeleton]# docker run -d -p 80:5000 -v $(pwd):/skeleton --name flask ...