单例模式

  单例模式,顾名思义,在程序运行中,实例化某个类时只实例化一次,即只有一个实例对象存在。例如在古代,一个国家只能有一个皇帝,在现代则是主席或总统等。

  在Java语言中单例模式有以下实现方式

1.饿汉式

import org.junit.jupiter.api.Test;

public class Singleton {
//静态成员变量
private static Singleton singleton = new Singleton();
private String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
//构造函数私有化
private Singleton(){
}
//返回静态资源中Singleton实例
public static Singleton getInstance() {
return singleton;
}
/**
* 单元测试
*/
@Test
public void testSingleton() {
//通过调用类的静态方法返回类的实例对象
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
s1.setName("zhangsan");
s2.setName("lisi");
System.out.println(s1.getName());
System.out.println(s2.getName());
}
}

  在类加载时,直接将实例对象初始化,并且该实例是静态的,属于类的成员变量,通过调用类的静态方法返回该对象。  

  运行testSingleton单元测试,输出的两行都是lisi,因为s1,s2指向的同一个实例对象,这个对象在类创建的时候就存在了。

  饿汉式是线程安全的,不管系统的那一个线程获取这个对象,他们都是该类同一个对象。缺点是在程序在一开始就创建了该对象,占用内存空间。下面这种实现方式增加判断,在程序调用时才实例化该对象。

2.懒汉式

import org.junit.jupiter.api.Test;

public class Singleton {
//不初始化实例对象
private static Singleton singleton = null;
private String name; public String getName() {
return name;
}
//构造函数私有化
private Singleton(){
}
public void setName(String name) {
this.name = name;
}
//当被调用时才动态实例化
public static Singleton getInstance() {
if(singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}

  懒汉式解决了饿汉式的实例对象初始化占用内存的情况,但是懒汉式存在线程安全的问题,当多个线程同时访问getInstance()方法时,有可能在第一个线程进入if语句是还没new Singleton()时,这时第二个线程判断if的时候就会为真,则会创建新的实例,单例模式设计失败。

  这时需要在getInstance()方法上添加synchronized修饰符,表示线程同步,即当一个线程访问该方法时,其他线程需要等待其释放资源。

public static synchronized Singleton getInstance() {
if(singleton == null) {
singleton = new Singleton();
}
return singleton;
}

  这样解决了懒汉式的线程不安全的问题,但是这样会降低系统的性能,当一个线程占用了该资源,其他的线程只能等待,系统的性能大大下降。于是乎第三种实现模式,对懒汉式进行了改进。

3.双重检测

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

  双重检测,线程访问时有两次检测。

  这里将synchronized放到判断语句里面,这样当第一个线程调用getInstance()方法时,singleton为空,进入synchronized代码块,其他的线程即使也判断singleton为空,则需要等待第一个线程完成资源的使用,这样保证了线程的安全。

  当实例化对象完成时,其他的线程调用getInstance()方法时,直接返回Singleton对象即可,不用再等待,这一点优化了系统,提高了系统的性能。

4.总结

  模式来源于生活。本文用Java语言实现了单例模式。三种实现方式都是线程安全的,饿汉式比较占用内存空间;懒汉式则降低了系统的性能;双重检测是懒汉式的升级,即能保证线程的安全,也能以懒加载的方式实现单例模式,在大规模系统中节省对象的创建时间,提高系统的性能。在系统中共享同一个资源或同一个对象,则可利用单例模式来实现。

  参考B站视频https://www.bilibili.com/video/av34162848

单例模式--java代码实现的更多相关文章

  1. 让JAVA代码跑得更快

    本文简单介绍一下在写代码过程中用到的一些让JAVA代码更高效的技巧. 1.   将一些系统资源放在池中(如数据库连接, 线程等) 在standalone的应用中, 数据库连接池可以使用一些开源的连接池 ...

  2. ActiveMQ——activemq的使用java代码实例(精选)

    ActiveMQ 在java中的使用,通过单例模式.工厂实现 Jms规范里的两种message传输方式Topic和Queue,两者的对比如下表():   Topic Queue 概要 Publish  ...

  3. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  4. 怎样编写高质量的java代码

    代码质量概述     怎样辨别一个项目代码写得好还是坏?优秀的代码和腐化的代码区别在哪里?怎么让自己写的代码既漂亮又有生命力?接下来将对代码质量的问题进行一些粗略的介绍.也请有过代码质量相关经验的朋友 ...

  5. 数据结构笔记--二叉查找树概述以及java代码实现

    一些概念: 二叉查找树的重要性质:对于树中的每一个节点X,它的左子树任一节点的值均小于X,右子树上任意节点的值均大于X. 二叉查找树是java的TreeSet和TreeMap类实现的基础. 由于树的递 ...

  6. java代码的初始化过程研究

        刚刚在ITeye上看到一篇关于java代码初始化的文章,看到代码我试着推理了下结果,虽然是大学时代学的知识了,没想到还能做对.(看来自己大学时掌握的基础还算不错,(*^__^*) 嘻嘻……)但 ...

  7. JDBC——Java代码与数据库链接的桥梁

    常用数据库的驱动程序及JDBC URL: Oracle数据库: 驱动程序包名:ojdbc14.jar 驱动类的名字:oracle.jdbc.driver.OracleDriver JDBC URL:j ...

  8. 利用Java代码在某些时刻创建Spring上下文

    上一篇中,描述了如何使用Spring隐式的创建bean,但当我们需要引进第三方类库添加到我们的逻辑上时,@Conponent与@Autowired是无法添加到类上的,这时,自动装配便不适用了,我们需要 ...

  9. lombok 简化java代码注解

    lombok 简化java代码注解 安装lombok插件 以intellij ide为例 File-->Setting-->Plugins-->搜索"lombok plug ...

随机推荐

  1. J2EE--常见面试题总结 -- (二)

    1 Spring拦截器的基本功能是什么? 拦截器是基于Java的反射机制的,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单 ...

  2. 一个简单的小小记账本程序(java)

    感觉基础知识学了不少,但是一直搞不清一个项目的实际开发流程,所以就借着这个小记账本的程序梳理一下.因为楼主也是出于学习阶段的菜鸟,所以程序可能会有各种玄学的bug,希望一起提升吧. 跟着站长学到了很多 ...

  3. oracle数据库语句积累

    1.从一个表选出数据更新另一个表(后面的exists一定要加) update jqhdzt set shid = (select shid from v_plat_userjqinfo t where ...

  4. VS下使用Google Protobuf完成SOCKET通信

    如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信 出处:如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信 最近一 ...

  5. DOM4J熟知

    什么是解析xml 系统最终会从xml中读取数据. 读取的过程就是解析. CRUD ==> 增删改查 ==> create read update delete ==> 解析指的就是读 ...

  6. linux监控系统的状态

    1.命令w的第一行和uptime或者用upload2.system load averages 表示单位时间短内活动的进程数3.查看cpu的个数和核数processor.physical id 4.v ...

  7. Redis之实战篇(与Mybatis整合)

    摘要: 现在市面流行的java框架,一个是ssh(spring.struts2.hibernate),另一个是ssm(spring.springmvc.mybatis),由于之前已经有整合过ssm框架 ...

  8. MySQL 的性能(下篇)—— 性能优化方法

    简介 文中内容均为阅读前辈的文章所整理而来,参考文章已在最后全指明 本文分为上下两篇: 上篇:MySQL 的 SQL 执行分析 下篇:MySQL 性能优化 下面为下篇内容,分为以下部分: 一.创建表时 ...

  9. 区分命令行模式和Python交互模式

    命令行模式 在Windows开始菜单选择"命令提示符",就进入到命令行模式,它的提示符类似C:\> Python交互模式 在命令行模式下敲命令python,就看到类似如下的一 ...

  10. php-msf 源码解读【转】

    php-msf: https://github.com/pinguo/php-msf 百度脑图 - php-msf 源码解读: http://naotu.baidu.com/file/cc7b5a49 ...