java设计模式1——单例模式
java设计模式1——单例模式
1、单例模式介绍
1.1、核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
1.2、常见场景

1.3、单例模式的优点

1.4、常见的五种单例模式实现方式

2、饿汉式
2.1、第一步:私有化构造器。(防止外部直接new对象)
//保证类只有一个实例,私有其构造器
private SingletonDemo01() {
}
2.2、第二步:创建自身对象。
//创建自身对象
private static SingletonDemo01 instance = new SingletonDemo01();
2.3、第三步:提够对外全局公开的方法
//全局公开的方法
public static SingletonDemo01 getInstance() {
return instance;
}
2.4、测试是否为单例
class SingletonDemo01Test {
public static void main(String[] args) {
SingletonDemo01 instance = SingletonDemo01.getInstance();
SingletonDemo01 instance2 = SingletonDemo01.getInstance();
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
System.out.println(instance == instance2);
}
}
输出的结果为:
356573597
356573597
true
2.5、弊端分析:
饿汉式一上来就会对对象进行创建,不管后续有没有用到,如果对于较大内存的对象而后续也都没有用到,则会造成较大的内存空间的浪费。
2.6、本类全部代码
package com.xgp.company.第一种_单例模式.饿汉式;
/**
*
* 核心:保证一个类只有一个实例,并且提供一个范围该实例的全局访问点
*/
public class SingletonDemo01 {
//保证类只有一个实例,私有其构造器
private SingletonDemo01() {
}
//创建自身对象
private static SingletonDemo01 instance = new SingletonDemo01();
//全局公开的方法
public static SingletonDemo01 getInstance() {
return instance;
}
}
class SingletonDemo01Test {
public static void main(String[] args) {
SingletonDemo01 instance = SingletonDemo01.getInstance();
SingletonDemo01 instance2 = SingletonDemo01.getInstance();
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
System.out.println(instance == instance2);
}
}
3、懒汉式
目的:解决饿汉式可能存在的内存空间浪费的问题进行该进,不一上来就创建对象,而是在使用时再来创建对象。
3.1、懒汉式的代码如下:
public class SingletonDemo02 {
//保证类只有一个实例,私有其构造器
private SingletonDemo02() {
}
//创建自身对象,当时不用立即加载
private static SingletonDemo02 instance;
//全局公开的方法 synchronized作用:加锁 多线程进来时会不安全,效率较低
public static synchronized SingletonDemo02 getInstance() {
if(instance == null) {
instance = new SingletonDemo02();
}
return instance;
}
}
3.2、分析:代码中为什要使用synchronized关键字来进行上锁
考率一下多线程的情况下,如果没有上锁,两个线程A、B一前以后的很紧密的执行该方法,而此时A完成了初始化操作,但是还没有进行返回,B此时进入判断语句中,此时也为null,这样也会进行初始化操作,于是乎,就得到了两个对象了,违反了单例模式设计得原则。
3.3、弊端分析:
该方法使用了synchronized对一个返回得方法进行了上锁,该方法得执行效率会较慢。
4、DCL_懒汉式
目的:DCL_懒汉式又称为双重检测懒汉式,为了改进懒汉式效率不高的问题
4.1、该类的1版本的代码如下:
public class SingletonDemo03 {
//保证类只有一个实例,私有其构造器
private SingletonDemo03() {
}
//创建自身对象,当时不用立即加载 volatile作用:尽大可能的解决极端情况的问题
private volatile static SingletonDemo03 instance;
//全局公开的方法 synchronized作用:加锁 多线程进来时会不安全,效率较低
public static SingletonDemo03 getInstance() {
if(instance == null) {
//定一次进来时加锁,后面进来时就不加锁了,提高了效率
synchronized (SingletonDemo03.class) {
if(instance == null) {
instance = new SingletonDemo03();
}
}
}
return instance;
}
}
4.2、分析1版本代码:
同样考率多线程的情况下,A、B两线程相继的进入方法中,A率先获得初始化权力,进行上锁,进行对对象的创建,并且因为有volatile关键字,能够快速的将对象更新给B。如果B未进入判断语句中,则此时B中有该类对象了,直接返回了。如果B进入了判断语句中,但是A已经上锁了,也无法进入了,只有返回了。
4.3、1版本的弊端
1、再考虑多线程的极端情况,如果该类比较庞大,创建对象需要花费很长时间,B已经进入函数中了,而A创建对象的时间会比B走完该函数的时间长,则此时该函数将会返回B,而B=NULL。
2、该模式无法防止反射
4.4、版本2代码:
public class SingletonDemo03 {
//破坏两次都用反射创建对象
private static boolean flag = false;
//保证类只有一个实例,私有其构造器
private SingletonDemo03() {
//防治被反射
synchronized (SingletonDemo03.class) {
if(flag == false) {
flag = true;
}else {
throw new RuntimeException("不要试图用反射破坏单例");
}
}
}
//创建自身对象,当时不用立即加载 volatile作用:尽大可能的解决极端情况的问题
private volatile static SingletonDemo03 instance;
//全局公开的方法 synchronized作用:加锁 多线程进来时会不安全,效率较低
public static SingletonDemo03 getInstance() {
if(instance == null) {
//定一次进来时加锁,后面进来时就不加锁了,提高了效率
synchronized (SingletonDemo03.class) {
if(instance == null) {
instance = new SingletonDemo03();
}
}
}
return instance;
}
}
4.5、弊端分析
该版本同样未解决上面的问题,只是加大了反射获取对象的难度,反射破坏单例的代码如下:
class SingletonDemo03Test {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
/*
SingletonDemo03 instance1 = SingletonDemo03.getInstance();
SingletonDemo03 instance2 = SingletonDemo03.getInstance();
System.out.println(instance1 == instance2);
*/
Class<SingletonDemo03> clazz = SingletonDemo03.class;
//反射破坏单例
Constructor<SingletonDemo03> declaredConstructor = clazz.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
SingletonDemo03 instance1 = declaredConstructor.newInstance();
//破坏flag
Field flag = clazz.getDeclaredField("flag");
flag.setAccessible(true);
flag.set(clazz,false);
System.out.println(flag.get(clazz));
SingletonDemo03 instance2 = declaredConstructor.newInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
运行结果:
false
false
21685669
2133927002
5、静态内部类实现
该方式能够不适用synchronized提高效率,并且能够保证在多线程的情况下依旧是单例,代码如下:
public class SingletonDemo04 {
private SingletonDemo04() {
//防治被反射
synchronized (SingletonDemo04.class) {
if(InnerClass.instance != null) {
throw new RuntimeException("不要试图用反射破坏单例");
}
}
}
private static class InnerClass {
private static final SingletonDemo04 instance = new SingletonDemo04();
}
public static SingletonDemo04 getInstance() {
return InnerClass.instance;
}
}
6、利用枚举来实现
java中最为推荐的是使用枚举类来创建单例对象,因为枚举类有这纯天然的优势,无法被反射。点击进反射创建对象的newInstance()方法的源码中可以发现:
@CallerSensitive
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
此外,枚举类也本身就是单例的,所以使用枚举类来创建单例对象最为适合,而如今大多数的框架的单例也都是通过这样的方法进行创建的。代码如下:
/**
* 反射不能破坏枚举类型,枚举类纯天然的单例,最简单
*/
public enum SingletonDemo05 {
INSTANCE;
public SingletonDemo05 getInstance() {
return INSTANCE;
}
public String hello() {
return "Hello World!";
}
}
class SingletonDemo05Test {
public static void main(String[] args) {
SingletonDemo05 instance1 = SingletonDemo05.INSTANCE;
SingletonDemo05 instance2 = SingletonDemo05.INSTANCE.getInstance();
System.out.println(instance1 == instance2);
String hello = SingletonDemo05.INSTANCE.hello();
System.out.println(hello);
}
}
java设计模式1——单例模式的更多相关文章
- java 设计模式之单例模式
-------Success is getting what you want, happiness is wanting what you get. java设计模式之单例模式(Singleton) ...
- 折腾Java设计模式之单例模式
博文原址:折腾Java设计模式之单例模式 单例模式 Ensure a class has only one instance, and provide a global point of access ...
- Java设计模式之单例模式(七种写法)
Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton { private static Singleto ...
- Java 设计模式之单例模式(一)
原文地址:Java 设计模式之单例模式(一) 博客地址:http://www.extlight.com 一.背景 没有太多原由,纯粹是记录和总结自己从业以来经历和学习的点点滴滴. 本篇内容为 Java ...
- java设计模式之单例模式你真的会了吗?(懒汉式篇)
java设计模式之单例模式你真的会了吗?(懒汉式篇) 一.什么是单例模式? 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供 ...
- java设计模式之单例模式(几种写法及比较)
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
- java设计模式- (1)单例模式
参加校园招聘的笔试,发现公司都会考一些java设计模式,所以上网查询相关内容,总结常用的几种单例模式. 单例模式(Singleton Pattern)是 Java中最简单的设计模式之一.这种类型的设计 ...
- [转]JAVA设计模式之单例模式
原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主 ...
- java设计模式之单例模式(七种方法)
单例模式:个人认为这个是最简单的一种设计模式,而且也是在我们开发中最常用的一个设计模式. 单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个 ...
随机推荐
- mybatis增强工具MyBatis-plus
如果你正在用mybatis,那MyBatis-plus你不能错过,配合使用可极大简化开发.提高效率! 简介 MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis ...
- [转载收藏]C#基础知识梳理系列十一:垃圾回收机制
摘 要 基于.NET平台的开发语言中,最让开发人员爽的一点就是垃圾回收处理机制,在编码过程中,终于可以解放你的双手来关注更重要的事情.很多的资料中在讲到.NET中的垃圾回收机制时都说"CLR ...
- 基于python的感知机
一. 1.感知机可以描述为一个线性方程,用python的伪代码可表示为: sum(weight_i * x_i) + bias -> activation #activation表示激活函数,x ...
- 20200104模拟赛 问题A 图样
题目 分析: 老规矩,遇到期望要准备好随时投降... 大致想到了按位处理,然后分别下去搜索,再用组合数加加减减一下... 但是两个连通块之间连边的期望怎么算呢? 很好,投降... 下来看题解... 果 ...
- 双指针,BFS和图论(二)
(一)BFS 1.地牢大师 你现在被困在一个三维地牢中,需要找到最快脱离的出路! 地牢由若干个单位立方体组成,其中部分不含岩石障碍可以直接通过,部分包含岩石障碍无法通过. 向北,向南,向东,向西,向上 ...
- Java容器解析系列(15) HashTable Dictionary & Properties
HashTable的实现原理与HashMap没有什么区别; 其与HashMap的主要区别如下: 添加进入jdk时间:HashTable在jdk1.0时添加,HashMap在jdk1.2时添加; 类签名 ...
- python3.6的安装及cx_oracle安装
一.创建所需目录mkdir -p /home/用户名/software/python3.6.1mkdir -p /home/用户名/priv/bydmkdir -p /home/用户名/priv/by ...
- LXC(LinuX Container)之namespaec和cgroup
LXC(LinuX Container)之namespaec和cgroup namespace概述 从操作系统级上实现了资源的隔离,它本质上是宿主机上的进程(容器进程),所以资源隔离主要就是指进程资源 ...
- CTF--HTTP服务--路径遍历(提升root用户权限)
开门见山 1. 在上次实验取的靶机低用户权限,查看该系统的内核版本 2. 查看该系统的发行版本 3. 查看该内核版本是否存在内核溢出漏洞,并没有 如果有内核溢出漏洞,则可以 4. 在靶机查看/etc/ ...
- Iptables和Firewall-selinux
一.Iptables防火墙 ---------- **三表五链:**三表: filter过滤表 nat转换表 mangle表五链: PREROUTING--->在进行路由选择前处理数据包 INP ...