基于Java利用static实现单例模式

目录
  • 一、之前旧的写法
  • 二、static代码块的效果
  • 三、单例的另一种写法
  • 四、总结

一、之前旧的写法

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

就利用Sington.getInstace就可以了,获得的是同一个实例。

上面那个代码有两个优点:

  • 懒加载,把在堆创建实例这个行为延迟到类的使用时。
  • 锁效果,防止生成多个实例,因为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帮我们做了两件事:

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

三、单例的另一种写法

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

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

四、总结

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

到此这篇关于基于Java利用static实现单例模式的文章就介绍到这了,更多相关static实现单例模式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java基础之static的用法

    一.前言 在java中static可以用来修饰以下内容: 成员变量 静态变量,可以直接通过类名去访问 成员方法 静态方法,可以直接通过类名去访问 代码块 静态代码块,当java虚拟机加载类时,就会执行该代码块 二.static修饰成员变量 成员变量 静态变量,可以直接通过类名去访问 2.1 类的成员变量 类的成员变量包括 类变量(静态变量) 被static修饰的变量 在内存中只有一个拷贝 类内部,可以在任何方法内直接访问静态变量 其它类中,可以直接通过类名访问 实例变量 没有被static修饰的

  • Java中的static关键字深入理解

    在学习Java以来很长一段时间,我都不能理解为什么修饰一个方法的关键字各不相同,为什么有的方法可以直接调用,而有的方法需要用对象才能调用.毫不夸张的说,最近一次让我决定去整理清楚static关键字,是因为在写jdbc工具类时,其中通过静态代码块来实现加载驱动才让我对它有了新的认识. 通俗来讲,归为几点: 由static关键字修饰的方法或成员变量,不需依赖对象,就可直接访问.(通过 类名.方法名() 或 类名.属性 直接调用) static关键字不会影响到变量或方法的作用域 static关键字不允

  • Java基础之static关键字的使用讲解

    static关键字 在Java中,static是静态修饰关键字.用于修饰类的成员方法.类的成员变量,另外可以编写static代码块来优化程序性能:被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问. static关键字的作用 方便在没有创建对象的情况下来进行调用方法或者变量.被static关键字修饰的方法或者变量不需要依赖对象来进行访问,只要类被加载了,就可以通过类名去访问. 1.static修饰成员方法 static修饰的方法称为静态方法

  • 带你了解Java中Static关键字的用法

    目录 Java中Static关键字的一些用法详解 1. Static 修饰类属性,因为静态成员变量可以通过类名+属性名调用,非静态成员变量不能通过类名+属性名调用: 2. Static 修饰类方法,可以通过类名.静态方法名的方式调用静态方法,不可以用类名.静态方法名调用非静态方法: 3. 静态代码块,匿名代码块,构造函数.三者的调用顺序为(静态代码块(只调用1次) --> 匿名代码块 --> 构造函数). 总结 Java中Static关键字的一些用法详解 1. Static 修饰类属性,因为静

  • java中static的用法及注意点

    在关键词的使用上,我们已经对static方法有所了解,为了防止在使用时出现一些不必要的错误,了解它的使用范围是每个人都要掌握的.本篇把static的使用注意点分为两个方面,一个是访问的范围,另一个是有关方法调用的注意,下面我们一起来看看完整的static使用注意点吧. 1.使用static方法的时候,只能访问static声明的属性和方法,而非static声明的属性和方法是不能访问的. package com.jk.ref; class People{ String name; private s

  • 解析Java中的static关键字

    一.static关键字使用场景 static关键字主要有以下5个使用场景: 1.1.静态变量 把一个变量声明为静态变量通常基于以下三个目的: 作为共享变量使用 减少对象的创建 保留唯一副本 第一种比较容易理解,由于static变量在内存中只会存在一个副本,所以其可以作为共享变量使用,比如要定义一个全局配置.进行全局计数.如: public class CarConstants { // 全局配置,一般全局配置会和final一起配合使用, 作为共享变量 public static final in

  • 基于Java利用static实现单例模式

    目录 一.之前旧的写法 二.static代码块的效果 三.单例的另一种写法 四.总结 一.之前旧的写法 class Singleton{     private Singleton() {}     private static Singleton instance = null;     public synchronized static Singleton getInstance() {             if (instance == null) {                

  • 基于Java 利用Mybatis实现oracle批量插入及分页查询

    目录 1.单条数据insert 2.批量数据批量insert 3.创建序列 4.oracle分页查询 前端与后端交互,分页查询 后端海量数据导出,批量查询 1.单条数据insert <!--简单SQL--> insert into userinfo (USERID, USERNAME, AGE) values(1001,'小明',20); <!--Mybatis写法1,有序列,主键是自增ID,主键是序列--> <insert id="insert" par

  • 基于java中的流程控制语句总结(必看篇)

    程序的结构分类: 顺序结构:按照写代码的顺序 一次执行 选择结构:根据条件的不同有选择的执行不同的代码 循环结构:在一定条件下 反复执行某一片代码 选择结构: 也叫分支结构 根据条件的不同,有选择的执行某一片代码 ,Java提供了两种 if结构 switch结构 if分为三种格式: if的第一种格式 if(条件){ 语句块 } 执行流程: 先判断条件, 如果为真 则语句块执行,否则 语句块不执行 代码演示: public static void main(String[] args) { Sys

  • 基于JAVA文件中获取路径及WEB应用程序获取路径的方法

    1. 基本概念的理解 `绝对路径`:你应用上的文件或目录在硬盘上真正的路径,如:URL.物理路径 例如: c:/xyz/test.txt代表了test.txt文件的绝对路径: http://www.sun.com/index.htm也代表了一个URL绝对路径: `相对路径`:相对与某个基准目录的路径,包含Web的相对路径(HTML中的相对目录). 例如: 在Servlet中,"/"代表Web应用的根目录,和物理路径的相对表示. 例如: "./"代表当前目录,&quo

  • 基于Java中最常用的集合类框架之HashMap(详解)

    一.HashMap的概述 HashMap可以说是Java中最常用的集合类框架之一,是Java语言中非常典型的数据结构. HashMap是基于哈希表的Map接口实现的,此实现提供所有可选的映射操作.存储的是对的映射,允许多个null值和一个null键.但此类不保证映射的顺序,特别是它不保证该顺序恒久不变. 除了HashMap是非同步以及允许使用null外,HashMap 类与 Hashtable大致相同. 此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性

  • 基于Java 生产者消费者模式(详细分析)

    生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放进篮子里(集合或数组),同时,消费者线程(一个或多个)从篮子里(集合或数组)取出面包消耗.虽然它们任务不同,但处理的资源是相同的,这体现的是一种线程间通信方式. 本文将先说明单生产者单消费者的情况,之后再说明多生产者多消费者模式的情况.还会分别使用wait()/nofity()/nofityAll()机制.lock()/unlock()机制实现这两种模式. 在开始介绍模式之前,先解释下wait().notify()和no

  • Java双重检查加锁单例模式的详解

    什么是DCL DCL(Double-checked locking)被设计成支持延迟加载,当一个对象直到真正需要时才实例化: class SomeClass { private Resource resource = null; public Resource getResource() { if (resource == null) resource = new Resource(); return resource; } } 为什么需要推迟初始化?可能创建对象是一个昂贵的操作,有时在已知的运

  • 基于java时区转换夏令时的问题及解决方法

    一.准备知识 1.America/New_York的夏令时时间如下: 包左不包右 2016-3-13, 02:00:00到2016-11-6, 02:00:00 2017-3-12, 02:00:00到2017-11-5, 02:00:00 2.三字母时区 ID 为了与 JDK 1.1.x 兼容,一些三字母时区 ID(比如 "PST"."CTT"."AST")也受支持. 但是,它们的使用被废弃,这是因为相同的缩写经常用于多个时区 例如 CST:有

  • 基于Java实现ssh命令登录主机执行shell命令过程解析

    这篇文章主要介绍了基于Java实现ssh命令登录主机执行shell命令过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.SSH命令 SSH 为 Secure Shell的缩写,由 IETF 的网络小组(Network Working Group)所制定:SSH 为建立在应用层基础上的安全协议.SSH 是较可靠,专为远程登录会话和其他网络服务提供安全性的协议.利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题.SSH最初是UNI

  • 基于Java的Socket编写的C/S聊天程序实现

    一个很久以前写的能够支持C/S模式聊天的Demo,利用Java的Socket写的. 只能聊一句就下线,挺low的. 服务器端程序Server import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class TestTcpServer { pub

随机推荐