Java单例模式的几种常见实现方式

懒汉or饿汉?

  • 懒汉:单例模式延迟加载方式,一开始不给你new对象,你要new再给你new
  • 饿汉:上来就给你new好一个对象,你可以直接用(吃),你也没法new

饿汉:不加锁,线程安全,用起来方便,容易产生垃圾对象

public class SingletonTest1 {
public static void main(String[] args) {
//由于构造方法是私有的,则外界无法实例化该类
//Singleton1 singleton1 = new Singleton1();
new Thread(() -> {
Singleton1 singleton1 = Singleton1.getInstance();
}).start(); Singleton1 singleton2 = Singleton1.getInstance();
}
} class Singleton1 {
//类加载时直接通过声明调用构造方法初始化
private static volatile Singleton1 singleton1 = new Singleton1(); //让构造函数为private,这样该类不会被外部调用实例化对象
private Singleton1(){
check();
} //通过静态方法提供外界获取该唯一可用对象的窗口
//直接给你用,你也别想着什么时候创建了
public static Singleton1 getInstance() {
return singleton1;
} //第一次创建实例就打印
private static void check() {
System.out.println("第一次创建该类的唯一实例才会打印这句话");
}
}

输出:

第一次创建该类的唯一实例才会打印这句话

单线程下的单例模式(懒汉,线程不安全)

这种方式只能在单线程环境中实现单例模式

public class SingletonTest1 {
public static void main(String[] args) {
//由于构造方法是私有的,则外界无法实例化该类
//Singleton1 singleton1 = new Singleton1(); //只可以通过实例化的方式
Singleton1 singleton1 = Singleton1.getInstance();
Singleton1 singleton2 = Singleton1.getInstance();
singleton1.test();
}
} class Singleton1 {
//默认初始化为null
private static Singleton1 singleton1; //让构造函数为private,这样该类不会被外部调用实例化对象
private Singleton1(){} //通过静态方法提供外界获取该唯一可用对象的窗口
//如果唯一的实例没有创建就负责创建,否则返回唯一的对象引用
public static Singleton1 getInstance() {
if (singleton1 == null) {
check();
singleton1 = new Singleton1();
}
//第二次创建就不会新建一个对象,而是传回之前已经创建的对象实例
return singleton1;
} //一个实例方法,用于证明实例化成功
public void test() {
System.out.println("测试方法,证明确实获得到了唯一实例");
} //第一次创建实例就打印
private static void check() {
System.out.println("第一次创建该类的唯一实例才会打印这句话");
}
}

输出:

第一次创建该类的唯一实例才会打印这句话
//显然第二次获取实例时只是获得到了之前创建的实例
测试方法,证明确实获得到了唯一实例

多线程下的单例模式(一)(懒汉,线程安全)

区别在于将方法上锁(这里也可以采用重入锁),我们来分析一下具体的工作环境,A线程为了检测是否新建的了实例,对get方法上锁,开始检测对象是否为null,并调用构造方法,返回对象...B线程试图中途获得锁被阻塞,然后等A线程释放锁之后,B获得锁去检测是否创建了对象,发现已经创建,就返回对象释放锁...

public class SingletonTest1 {
public static void main(String[] args) {
//由于构造方法是私有的,则外界无法实例化该类
//Singleton1 singleton1 = new Singleton1();
new Thread(() -> {
Singleton1 singleton1 = Singleton1.getInstance();
}).start(); Singleton1 singleton2 = Singleton1.getInstance();
}
} class Singleton1 {
//默认初始化为null
private static Singleton1 singleton1; //让构造函数为private,这样该类不会被外部调用实例化对象
private Singleton1(){} //通过静态方法提供外界获取该唯一可用对象的窗口
//如果唯一的实例没有创建就负责创建,否则返回唯一的对象引用
public synchronized static Singleton1 getInstance() {
if (singleton1 == null) {
check();
singleton1 = new Singleton1();
}
//第二次创建就不会新建一个对象,而是传回之前已经创建的对象实例
return singleton1;
} //一个实例方法,用于证明实例化成功
public void test() {
System.out.println("测试方法,证明确实获得到了唯一实例");
} //第一次创建实例就打印
private static void check() {
System.out.println("第一次创建该类的唯一实例才会打印这句话");
}
}

输出:

第一次创建该类的唯一实例才会打印这句话

多线程下的单例模式(二)(双重检测)

这里要注意:上锁解锁的很消耗时间空间的,而这里无论对象是否存在,都先上锁,再去检测,显然是没有必要的,当线程很多的时候会造成资源大量的浪费~可以先检测对象是否存在,如果对象不存在再试图申请锁去创建资源,则会节约资源并达到线程安全的目的——双重检测

public class SingletonTest1 {
public static void main(String[] args) {
//由于构造方法是私有的,则外界无法实例化该类
//Singleton1 singleton1 = new Singleton1();
new Thread(() -> {
Singleton1 singleton1 = Singleton1.getInstance();
}).start(); Singleton1 singleton2 = Singleton1.getInstance();
}
} class Singleton1 {
//默认初始化为null,volatile:主内存 工作内存
private static volatile Singleton1 singleton1; //让构造函数为private,这样该类不会被外部调用实例化对象
private Singleton1(){} //通过静态方法提供外界获取该唯一可用对象的窗口
//如果唯一的实例没有创建就负责创建,否则返回唯一的对象引用
public static Singleton1 getInstance() {
if (singleton1 == null) {
synchronized (Singleton1.class) {
//两个贤臣可能都越过了外层的null检测,所以可能进入后已经不是null了
if (singleton1 == null) {
check();
singleton1 = new Singleton1();
}
}
}
return singleton1;
} //一个实例方法,用于证明实例化成功
public void test() {
System.out.println("测试方法,证明确实获得到了唯一实例");
} //第一次创建实例就打印
private static void check() {
System.out.println("第一次创建该类的唯一实例才会打印这句话");
}
}

Java单例模式的几种常见实现方式的更多相关文章

  1. java单例模式的几种写法比较

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  2. Java 单例模式的七种写法

    Java 单例模式的七种写法 第一种(懒汉,线程不安全) public class Singleton { private static Singleton instance; private Sin ...

  3. 单例模式:Java单例模式的几种写法及它们的优缺点

    总结下Java单例模式的几种写法: 1. 饿汉式 public class Singleton { private static Singleton instance = new Singleton( ...

  4. Linux下几种常见压缩方式测试对比

    目录 Linux下几种常见压缩方式测试对比 参考 简介 测试 总结 Linux下几种常见压缩方式测试对比

  5. JAVA中的四种JSON解析方式详解

    JAVA中的四种JSON解析方式详解 我们在日常开发中少不了和JSON数据打交道,那么我们来看看JAVA中常用的JSON解析方式. 1.JSON官方 脱离框架使用 2.GSON 3.FastJSON ...

  6. Redis 的几种常见使用方式

    常见使用方式 Redis 的几种常见使用方式包括: Redis 单副本 Redis 多副本(主从) Redis Sentinel(哨兵) Redis Cluster Redis 自研 各种使用方式的优 ...

  7. java中的线程(2):如何正确停止线程之3种常见停止方式

    1.常见停止方式 自定义线程,其中含退出标志位,在run中判断它. 使用interrupt()方法中断线程 使用stop方法暴力终止(已经弃用) 2.使用标志位 class TestThread ex ...

  8. java中的线程(2):如何正确停止线程之2种常见停止方式

    1.常见停止方式 结束run函数,run中含退出标志位. 使用interrupt()方法中断线程 使用stop方法暴力终止(已经弃用) 2.结束run class TestThread extends ...

  9. Java单例模式的6种写法

    在Java中,单例有很多种写法,面试时,手写代码环节,除了写算法题,有时候也会让手写单例模式,这里记录一下单例的几种写法和优缺点. 初级写法 懒汉式 饿汉式 双锁检验 内部类 枚举式 1.初级写法 p ...

  10. java实践经验几种常见数据库连接池的使用比较

    经历的几个产品及项目中,包括了各种数据库及应用服务器,基本上几种常见的数据库连接池都用到了,根据使用的情况把这些连接池比较一下吧.(http://m.0834jl.com) 感觉在介绍之前有必要阐述一 ...

随机推荐

  1. pandas -- DataFrame的级联以及合并操作

    博客地址:https://www.cnblogs.com/zylyehuo/ 开发环境 anaconda 集成环境:集成好了数据分析和机器学习中所需要的全部环境 安装目录不可以有中文和特殊符号 jup ...

  2. Asp-Net-Core开发笔记:快速在已有项目中引入EFCore

    前言 很多项目一开始选型的时候没有选择EFCore,不过EFCore确实好用,也许由于种种原因后面还是需要用到,这时候引入EFCore也很方便. 本文以 StarBlog 为例,StarBlog 目前 ...

  3. 自定义MyBatis拦截器更改表名

    by emanjusaka from ​ https://www.emanjusaka.top/archives/10 彼岸花开可奈何 本文欢迎分享与聚合,全文转载请留下原文地址. 自定义MyBati ...

  4. 模拟ASP.NET Core MVC设计与实现

    前几天有人在我的<ASP.NET Core框架揭秘>读者群跟我留言说:"我最近在看ASP.NET Core MVC的源代码,发现整个系统太复杂,涉及的东西太多,完全找不到方向,你 ...

  5. 【Spring】事务实现原理

    在使用事务的时候需要添加@EnableTransactionManagement注解来开启事务,Spring事务底层是通过AOP来实现的,所以启用事务后,同样会向容器中注入一个代理对象创建器,AOP使 ...

  6. (转)用GPU做DeepLearning要比CPU快40~80倍

    The speed difference of CPU and GPU can be significant in deep learning. But how much? Let's do a te ...

  7. .NET8依赖注入新特性Keyed services

    什么是Keyed service Keyed service是指,为一个需要注入的服务定义一个Key Name,并使用使用Key Name检索依赖项注入 (DI) 服务的机制. 使用方法 通过调用 A ...

  8. 【源码系列#01】vue3响应式原理(Proxy)

    专栏分享:vue2源码专栏,vue3源码专栏,vue router源码专栏,玩具项目专栏,硬核推荐 欢迎各位ITer关注点赞收藏 在学习 Vue3 是如何进行对象的响应式代理之前,我想我们应该先去了解 ...

  9. Numpy理解

    目录 什么是numpy numpy的安装 numpy数组 定义numpy数组 numpy数组的相关功能 基本操作 0数组和1数组 随机数组 二维数组 numpy的数组操作 我们再平常学习python和 ...

  10. 每天5分钟复习OpenStack(十)Ceph 架构

    在很多关于Ceph的文章中,通常会介绍一堆概念.虽然这些概念很重要,但是对于一个新手来说,同时接受太多的概念实际上很难消化.因此,在阅读本章节时要保持轻松的心情,只需要对所有的概念有个了解就可以了,因 ...