概述

上一篇日志中,我们介绍了单例模式的概念和基础的应用

本节中,我们就来介绍一下 java 语言中如何编写单例模式类

只适合单线程环境的单例模式

public class Singleton {

private static Singleton instance = null;

private Singleton() { }

public static Singleton getInstance(){

if (instance == null) {

instance = new Singleton();

}

return instance;

}

}

这是单例模式的最简单实现,private 的构造方法保证了类不会被通过 new 的方式创建,同时,判断 instance 是否为 null 保证了单线程环境下单例模式运行的正确性

但是,正如我们反复强调的,这种方式是非线程安全的,原因在于,当多个线程并发执行,同时进行判断 instance 为 null 的操作,而此时 instance 确实为 null,那么所有的线程都将去创建一个单例的对象,这显然是我们不希望看到的,那么下面我们就来解决这个问题

通过同步锁实现线程安全

正如上面提到的,之所以存在线程安全问题,主要是因为判断 instance 是否为 null 与对象的创建是非原子性的,那么,我们只需要用锁来保证两个操作的原子性即可解决这个问题

public class Singleton {

private static Singleton instance = null;

private Singleton() { }

public static synchronized Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

}

但是加锁对性能是会造成影响的,在并发环境下,当一个线程运行到 synchronized 处,获取锁进入到 instance 的判断,其他所有的并发线程都必须在该线程执行完 instance 的创建操作后才能够继续执行,而事实上,一旦 instance 被创建,这样的等待都将会是白费的

双重校验锁

双重校验锁对上面的例子进行了优化

public class Singleton {

private static Singleton instance = null;

private Singleton() { }

public static Singleton getInstance() {

if (instance == null) {

synchronized (Singleton.class) {

if (instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

}

一旦对象被创建,那么程序将不会去请求获取锁而是直接返回 instance

最简单的线程安全单例模式

public class Singleton {

private static Singleton instance = new Singleton();

private Singleton() { }

public static Singleton getInstance() {

return instance;

}

}

这段代码看上去非常简单,他会在类首次被加载时创建单例的对象,jvm 会保证单例对象只被创建一次,但是有时我们仅仅是在代码中引用了这个类,或者仅仅调用了这个类中的其他方法,我们并不希望在我们还不需要通过 getInstance 方法获取对象的时候,对象就已经被创建了,这是这种方式的主要问题

静态内部类

public class Singleton {

private Singleton() {

}

private static class SingletonHolder {

private final static Singleton instance = new Singleton();

}

public static Singleton getInstance() {

return SingletonHolder.instance;

}

}

这种方式解决了上一种方式所存在的问题,仅在 getInstance 方法被调用时,对象才会被创建

使用枚举

public enum SingletonEnum {

BOOM_MAZE_FACTORY(new BoomMazeFactory()),

STANDARD_MAZE_FACTORY(new StandardMazeFactory()),

;

private MazeFactory mazeFactory;

public MazeFactory getMazeFactory() {

return mazeFactory;

}

SingletonEnum(MazeFactory mazeFactory) {

this.mazeFactory = mazeFactory;

}

}

由于枚举在项目中并不会被常常用到,这样的用法就更加难得一见了,而事实上,这才是最推荐的用法

微信公众号

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

标签

技术帖

技术分享

java

singleton

设计模式

模式

设计

单例

java 单例 实现_java 实现单例的各种方式相关推荐

  1. java 读取css文件_java文件读取的两种方式

    JAVA中读取文件(二进制,字符)内容的几种方 JAVA中读取文件内容的方法有很多,比如按字节读取文件内容,按字符读取文件内容,按行读取文件内容,随机读取文件内容等方法,本文就以上方法的具体实现给出代 ...

  2. java 单例设计_Java 之单例设计模式

    设计模式: 对问题行之有效的解决方式, 其实它是一种思想. 单例设计模式 解决的问题:就是可以保证一个类在内存中的对象唯一性. 即单个实例. 比如对于A 和 B 两个程序使用同一个配置信息对象时, A ...

  3. java 单链表反转_Java实现单链表翻转详解

    单链表翻转比如有如下链表: 需要按照C B A 输出,我们可以有好几种方法: package org.andy.test; import java.util.ArrayList; import jav ...

  4. java订单重复提交_java表单重复提交常用解决办法

    最近在看些基础的东西,顺便做下笔记.相信大家在平时网页使用中,经常会有按钮重复点击,然后点不动刷新,还有当网络延时比较厉害点了没反应在点击的重复提交.为了避免这种情况,总结了一下4点处理方案 表单重复 ...

  5. java 反转jia链表_Java实现单链表反转

    本文主要介绍单链表反转的两种方法,记录如下: 1. package com.leetcode; public class ListReverse { public static void main(S ...

  6. java如何实现定时任务_Java定时任务的三种实现方式

    前言 现代的应用程序早已不是以前的那些由简单的增删改查拼凑而成的程序了,高复杂性早已是标配,而任务的定时调度与执行也是对程序的基本要求了. 很多业务需求的实现都离不开定时任务,例如,每月一号,移动将清 ...

  7. java实现多线程抢单_JAVA实现多线程的四种方式

    JAVA多线程实现方式: 1.继承Thread类(无返回值) 2.实现Runnable接口(无返回值) 3.实现Callable接口,通过FutureTask包装器来创建Threak线程(有返回值) ...

  8. java中ajax概念_Java之AJAX概念和实现方式

    Java之AJAX概念和实现方式 开发工具与关键技术:MyEclipse 10,java 作者:刘东标 撰写时间:2019-06-12 1.概念: Asynchronous JavaScript An ...

  9. java用户输入解析_Java中的3种输入方式实现解析

    Java中的3种输入方式实现解析 发布于 2020-8-8| 复制链接 摘记: 这篇文章主要介绍了Java中的3种输入方式实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学 ...

最新文章

  1. java内存数据管理
  2. 路由器和交换机的综合实验
  3. 解读《德勤2017年全球CIO报告》:顶级CIO的炼成之道
  4. linux查看机器品牌信息,dmidecode查看linux硬件信息
  5. 不会还有人不会配置LLDP链路层发现协议吧?
  6. H264 TS/ES
  7. JS正则表达式大全【转】
  8. python基础查漏补缺1--算数、字符串与变量
  9. 男女薪酬差异扩大 2018年女性薪酬不及男性8成?
  10. nginx日志统计分析的相关常用命
  11. 【链表】两个链表的第一个公共结点
  12. Erlang中的record与宏
  13. 世界地图矢量文件shp格式获取/下载方法
  14. 基于R语言的贝叶斯网络模型、现代贝叶斯统计学方法
  15. php登陆注册加密函数,php加密函数_php用户自定义加密函数
  16. 十大排序算法Java版
  17. 对任意合式公式求真值表以及主析取范式和主合取范式(JAVA)
  18. 程序员在技术之外,还要掌握一个技能——自我营销能力
  19. 工作中你应该知道的常识(深度好文)
  20. Hadoop官网翻译 (HDFS命令)

热门文章

  1. 使用JCache缓存方法结果
  2. apache camel_令人印象深刻的第一个Apache Camel版本
  3. JavaOne 2015:为JDK 9做准备– blog @ CodeFX
  4. 使用Apache Drill深入研究当今的大数据
  5. JBoss Data Virtualization 6.1 Beta现在可用
  6. Java事实让您大吃一惊! (信息图)
  7. ThreadLocal如何实现?
  8. Java泛型面试问题
  9. 克隆可序列化和不可序列化的Java对象
  10. 在Java 7中处理文件