一:之前旧的写法

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

就利用Sington.getInstace就可以了,获得的是同一个实例。上面那个代码有两个优点:

  1. 懒加载,把在堆创建实例这个行为延迟到类的使用时。
  2. 锁效果,防止生成多个实例,因为synchronized修饰这个static方法,所以相当于给这个方法加上了一个类锁。

二:static代码块的效果

先来看一段代码:

class StaticClass{
private static int a = 1;
static{
System.out.println("语句1");
System.out.println("语句2");
}
static{
System.out.println("语句3");
System.out.println("语句4");
}
}

当在多个线程同时触发类的初始化过程的时候(在初始化过程,类的static变量会被赋值为JVM默认值并且static代码块会被执行),为什么static不会被多次执行?因为有可能两个线程同时检测到类还没被初始化,然后都执行static代码块,结果就把语句1234多打印了,为什么上述情况不会发生。

Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Class.forName("StaticClass");//这一行触发类的初始化导致静态代码块执行
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
});
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Class.forName("StaticClass");//同样
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
});
thread2.start();

结果如下:

语句1
语句2
语句3
语句4

有一段英文对其进行了解释:

static initialization block can be triggered from multiple parallel threads (when the loading of the class happens in the first time), Java runtime guarantees that it will be executed only once and in thread-safe manner + when we have more than 1 static block - it guarantees the sequential execution of the blocks, 也就是说,java runtime帮我们做了两件事:

  1. 并行线程中,都出现了第一次初始化类的情况,保证类的初始化只执行一次。
  2. 保证static代码块的顺序执行

三:单例的另一种写法

有了对static的知识的了解之后,我们可以写出这样的单例模式:

class Singleton{
private Singleton() {}
private static class NestedClass{
static Singleton instance = new Singleton();//这条赋值语句会在初始化时才运行
}
public static Singleton getInstance() {
return NestedClass.instance;
}
}
  1. 懒加载,因为static语句会在初始化时才赋值运行,达到了懒加载的效果。
  2. 锁的效果由Java runtime保证,虚拟机帮我们保证static语句在初始化时只会执行一次。

四:总结

如果不知道static的基础知识和虚拟机类加载的知识,我可能并不会知道这一种方法。理论永远先行于技术,要学好理论才能从根本上提升自己。

本博文站在以下这位巨人的肩膀上:https://www.linkedin.com/pulse/static-variables-methods-java-where-jvm-stores-them-kotlin-malisciuc

利用static来实现单例模式的更多相关文章

  1. JAVA Static方法与单例模式的理解

    近期用sonar測评代码质量的时候,发现一个问题,project中一些util类,曾经写的static方法都提示最好用单例的方式进行改正. 为此,我细致想了想,发现还是非常有道理的.这里谈谈我个人对s ...

  2. JDK设计模式之—单例模式和static关键字

    首先了解static 关键字 static声明的方法是静态方法,static声明的成员变量为静态成员变量.对于该类的所有对象来说,static的成员变量和static只有一份存储空间 即使没有创建该类 ...

  3. Java——static关键字

    前言 static关键字算是Java中比较复杂的关键字之一,它可以修饰变量.方法.类以及代码块.下面将介绍static的具体使用. static引入的目的 static的作用 static修饰变量 s ...

  4. iOS下单例模式实现(二)利用宏定义快速实现

    在上一节里提到了用利用gcd快速实现单例模式. 一个项目里面可能有好几个类都需要实现单例模式.为了更高效的编码,可以利用c语言中宏定义来实现. 新建一个Singleton.h的头文件. // @int ...

  5. 23种设计模式--单例模式-Singleton

    一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...

  6. 【白话设计模式四】单例模式(Singleton)

    转自:https://my.oschina.net/xianggao/blog/616385 0 系列目录 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factor ...

  7. 设计模式(4) -- 单例模式(Singleton)

    设计模式(4)  -- 单例模式(Singleton) 试想一个读取配置文件的需求,创建完读取类后通过New一个类的实例来读取配置文件的内容,在系统运行期间,系统中会存在很多个该类的实例对象,也就是说 ...

  8. Java设计模式-单例模式及线程安全问题

    单例模式是非常常用的设计模式,他确保了一个类只有一个对象,并且这个对象是自己创建的,外界可以获取使用到这个对象. 单例模式一般有两种:懒汉式,饿汉式(其实还有一种登记式,把创建的对象放在map集合中, ...

  9. 单例模式的优化之路(java)

    1.概述 最近在优化公司以前老项目的代码时,发现有些类的代码频繁地创建和销毁对象,资源消耗比较严重.针对这些做了一些优化,改用单例模式,避免频繁的创建和销毁对象,说起单例模式,相信每个人都会写,接下来 ...

随机推荐

  1. 你的Redis怎么持久化的

    一.持久化套路 OK,一般我们在生产上采用的持久化策略为 (1)master关闭持久化 (2)slave开RDB即可,必要的时候AOF和RDB都开启 该策略能够适应绝大部分场景,绝大部分集群架构. 为 ...

  2. 【Python机器学习实战】聚类算法(2)——层次聚类(HAC)和DBSCAN

    层次聚类和DBSCAN 前面说到K-means聚类算法,K-Means聚类是一种分散性聚类算法,本节主要是基于数据结构的聚类算法--层次聚类和基于密度的聚类算法--DBSCAN两种算法. 1.层次聚类 ...

  3. 主流微服务一站式解决方案Spring Cloud Alibaba入门看这篇就足够了

    学习路线 **本人博客网站 **IT小神 www.itxiaoshen.com 生态概述 架构演进 什么是微服务 https://martinfowler.com/microservices/ Mic ...

  4. SWPUCTF_2019_login(格式字符串偏移bss段)

    题目的例行检查我就不放了,将程序放入ida中 很明显的值放入了bss段的格式字符串,所以我们动态调试一下程序 可以看到ebp这个地方0xffd0dd17-->0xffd0dd38-->0x ...

  5. dump Java 程序和服务器相关信息

    #!/bin/bash jps -lm read -p "enter java pid: " pid port=$(netstat -ntlp | grep $pid | awk ...

  6. Tornado.web.Application之-settings

    应用程序配置 class  tornado.web.Application(handlers:List [Union [Rule,Tuple]] = None,default_host:str = N ...

  7. 好奇怪啊,如果邮箱JSON格式的字符串不是在一行上,那么转为JSON将转换不成功,估计是数据格式有问题吧

    好奇怪啊,如果邮箱JSON格式的字符串不是在一行上,那么转为JSON将转换不成功,估计是数据格式有问题吧, 打印出的数据必须是如下的在一行的字符串,才可以转换为JSON格式成功.

  8. 最强最全面的大数据SQL经典面试题(由31位大佬共同协作完成)

    本套SQL题的答案是由许多小伙伴共同贡献的,1+1的力量是远远大于2的,有不少题目都采用了非常巧妙的解法,也有不少题目有多种解法.本套大数据SQL题不仅题目丰富多样,答案更是精彩绝伦! 注:以下参考答 ...

  9. 『学了就忘』Linux日志管理 — 91、日志服务rsyslogd说明

    目录 1.日志文件格式 2.rsyslogd服务的配置文件 (1)rsyslog.conf文件内容 (2)rsyslog.conf配文件内容说明 (3)定义自己的日志 1.日志文件格式 只要是由日志服 ...

  10. IPtables 之“四表五链”

    目录 架构图 IP tables 简介 包过滤防火墙 Iptables如何过滤 "四表" "五链" Iptables流程 架构图 公司架构模式(酒店迎宾比喻) ...