Java单例模式的几种常见实现方式
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单例模式的几种常见实现方式的更多相关文章
- java单例模式的几种写法比较
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
- Java 单例模式的七种写法
Java 单例模式的七种写法 第一种(懒汉,线程不安全) public class Singleton { private static Singleton instance; private Sin ...
- 单例模式:Java单例模式的几种写法及它们的优缺点
总结下Java单例模式的几种写法: 1. 饿汉式 public class Singleton { private static Singleton instance = new Singleton( ...
- Linux下几种常见压缩方式测试对比
目录 Linux下几种常见压缩方式测试对比 参考 简介 测试 总结 Linux下几种常见压缩方式测试对比
- JAVA中的四种JSON解析方式详解
JAVA中的四种JSON解析方式详解 我们在日常开发中少不了和JSON数据打交道,那么我们来看看JAVA中常用的JSON解析方式. 1.JSON官方 脱离框架使用 2.GSON 3.FastJSON ...
- Redis 的几种常见使用方式
常见使用方式 Redis 的几种常见使用方式包括: Redis 单副本 Redis 多副本(主从) Redis Sentinel(哨兵) Redis Cluster Redis 自研 各种使用方式的优 ...
- java中的线程(2):如何正确停止线程之3种常见停止方式
1.常见停止方式 自定义线程,其中含退出标志位,在run中判断它. 使用interrupt()方法中断线程 使用stop方法暴力终止(已经弃用) 2.使用标志位 class TestThread ex ...
- java中的线程(2):如何正确停止线程之2种常见停止方式
1.常见停止方式 结束run函数,run中含退出标志位. 使用interrupt()方法中断线程 使用stop方法暴力终止(已经弃用) 2.结束run class TestThread extends ...
- Java单例模式的6种写法
在Java中,单例有很多种写法,面试时,手写代码环节,除了写算法题,有时候也会让手写单例模式,这里记录一下单例的几种写法和优缺点. 初级写法 懒汉式 饿汉式 双锁检验 内部类 枚举式 1.初级写法 p ...
- java实践经验几种常见数据库连接池的使用比较
经历的几个产品及项目中,包括了各种数据库及应用服务器,基本上几种常见的数据库连接池都用到了,根据使用的情况把这些连接池比较一下吧.(http://m.0834jl.com) 感觉在介绍之前有必要阐述一 ...
随机推荐
- svn: E200007: Retrieval of mergeinfo unsupported解决
http://blog.csdn.net/intlgj/article/details/39080605 svn: E200007: Retrieval of mergeinfo unsupport ...
- 这款 7k Star 的国产监控系统,真不错!
我们都知道天下没有"永不宕机"的系统,但每次线上出问题都要拉出一个程序员"祭天".所以一款靠谱.好用的监控工具就显得十分重要,它可以在生产环境出故障的第一时间发 ...
- mapState、mapGetters、mapMutations、mapActions学习
https://next.vuex.vuejs.org/zh/guide/state.html#mapstate-%E8%BE%85%E5%8A%A9%E5%87%BD%E6%95%B0 https: ...
- Pinely Round 2 (Div. 1 + Div. 2) (CF1863)
本来开了某场远古 Div 1,然后学了一堆前置知识至今仍然不会 E.换一场写来得及吗? A. Channel 模拟,略. B. Split Sort Description 给你一个长度为 \(n\) ...
- HarmonyOS UI 开发
引言 HarmonyOS 提供了强大的 UI 开发工具和组件,使开发者能够创建吸引人的用户界面.本章将详细介绍在 HarmonyOS 中应用 JS.CSS.HTML,HarmonyOS 的 UI 组件 ...
- 邮差之死--python源代码
"""sth imported""" import time import os '''2 flags''' flag = 0 tmp = ...
- 一篇文章带你了解Python常用自动化测试框架——Pytest
一篇文章带你了解Python常用自动化测试框架--Pytest 在之前的文章里我们已经学习了Python自带测试框架UnitTest,但是UnitTest具有一定的局限性 这篇文章里我们来学习第三方框 ...
- (Good topic)圆圈中最后剩下的数字(leetcode 3.30每日打卡)
著名的约瑟夫问题: 0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字.求出这个圆圈里剩下的最后一个数字. 例如,0.1.2.3.4这5个数字组成一个圆圈,从数字0开 ...
- 深入理解RC4加密算法
RC4(Rivest Cipher 4)是一种广泛应用的加密算法,由Ronald L. Rivest于1987年发明.它是一种流密码(stream cipher)算法,适用于对网络通信中的数据进行加密 ...
- 「有问必答」秒杀系统 Go并发编程实践!
有问必答 摘要 本文将介绍如何使用Go语言的并发原语来构建一个简单的高并发秒杀系统. 我们将使用Go语言的原生库和一些常见的技术手段,包括互斥锁.通道.计数器等,来解决并发访问和数据一致性的问题. 本 ...