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. fprintf

    fprintf 是一个标准C库函数,用于将格式化的输出写入到指定文件流中.它的函数原型如下: int fprintf(FILE *stream, const char *format, ...); 参 ...

  2. 其它——MyCat实现分库分表

    文章目录 MyCat实现分库分表 一 开源数据库中间件-MyCat 二 MyCat简介 三 MyCat下载及安装 3.1 MySQL安装与启动 3.2使用docker启动多个数据库 3.3 MyCat ...

  3. ORA-10456: cannot open standby database; media recovery session may be in progress

    SQL> alter database recover managed standby database disconnect from session;Database altered.SQL ...

  4. Chromium 通过IDL方式添加扩展API

    基于chromium103版本 1. 自定义扩展API接口 chromium默认扩展api接口中有chrome.runtime.*,和chrome.send.*等,现在我们就仿照chrome.runt ...

  5. IEDA-Maven项目开发步骤

    1. 打开IDEA 界面,选择"New Project" 2. 输入项目名称和基本信息 输入项目名称.选择存放路径.JDK版本.以及GroupId.ArtifactId. Grou ...

  6. QT打开摄像头(自定义取景器)

    自建取景器 .h #ifndef CAMERASURFACE_H #define CAMERASURFACE_H #include<QAbstractVideoSurface> #incl ...

  7. 开发现代化的.NetCore控制台程序:(3)将nuget包发布到GitHubPackages

    前言 上一篇文章已经把项目模板的nuget包发布到了 nuget 的官方源了,其实还可以发布到其他源,比如 GitHub ,本文记录一下发布到 GitHub Packages 的过程. 注意:本文建立 ...

  8. 2022.7.15 jiazhaopeng 讲课纪要

    前言 由于难度仍然过高,难度再次下调,这节课主要在水绿.这节课讲的是并查集,之所以是以绿题为主是因为上了绿之后的题有一大半都要结合别的东西,初中生不会,所以只能讲的简单一点. ORZ%%% jzp学长 ...

  9. 自实现string类

    一. 环境 Linux x86_64,g++ 8.5.0 二. 实现 自实现 string 之前一直想写来着,一直拖着,现在把它完稿.这个版本是比较简单的版本,有一些可能有不同的或者更好的实现方式,后 ...

  10. Linux机器自建账号并赋予sudo权限,同时修改远程端口

    默认使用root账号来操作Linux有一定风险,因此需要自建账号并赋予sudo权限,方便使用 登录为root用户后,创建账号 adduser <username> Ubuntu系统会同时要 ...