单利 java_Java设计模式-单利模式

单例模式

作为对象的创建模式,单例模式确保其某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类。单例模式有以下特点:

1、单例类只能有一个实例

2、单例类必须自己创建自己的唯一实例

3、单例类必须给其他所有对象提供这一实例

下面看一下单例模式的三种写法,除了这三种写法,静态内部类的方式、静态代码块的方式、enum枚举的方式也都可以,不过异曲同工,这三种方式就不写了。

首先声明就是 在我们项目工程中 我们完全不用使用懒汉式 因为有锁使用的地方就有效率低的存在;

饿汉式

顾名思义,饿汉式,就是使用类的时候不管用的是不是类中的单例部分,都直接创建出单例类,看一下饿汉式的写法:

public classSingleEager {public static SingleEager se = newSingleEager();public staticSingleEager getInstance()

{returnse;

}

}

这就是饿汉式单例模式的写法,也是一种比较常见的写法。这种写法会不会造成竞争,引发线程安全问题呢?答案是不会。

可能有人会觉得奇怪:第3行,CPU执行线程A,实例化一个EagerSingleton,没有实例化完,CPU就从线程A切换到线程B了,线程B此时也实例化这个EagerSingleton,然后EagerSingleton被实例化出来了两次,有两份内存地址,不就有线程安全问题了吗?

没关系,我们完全不需要担心这个问题,JDK已经帮我们想到了。Java虚拟机2:Java内存区域及对象,文中可以看一下对象创建这一部分,没有写得很详细,其实就是"虚拟机采用了CAS配上失败重试的方式保证更新更新操作的原子性和TLAB两种方式来解决这个问题"。

懒汉式

同样,顾名思义,这个人比较懒,只有当单例类用到的时候才会去创建这个单例类,看一下懒汉式的写法:

public classLazySingleton

{private static LazySingleton instance = null;privateLazySingleton()

{

}public staticLazySingleton getInstance()

{if (instance == null)

instance= newLazySingleton();returninstance;

}

}

这种写法基本不用,因为这是一种线程非安全的写法。试想,线程A初次调用getInstance()方法,代码走到第12行,线程此时切换到线程B,线程B走到12行,看到instance是null,就new了一个LazySingleton出来,这时切换回线程A,线程A继续走,也new了一个LazySingleton出来。这样,单例类LazySingleton在内存中就有两份引用了,这就违背了单例模式的本意了。

可能有人会想,CPU分的时间片再短也不至于getInstance()方法只执行一个判断就切换线程了吧?问题是,万一线程A调用LazySingleton.getInstance()之前已经执行过别的代码了呢,走到12行的时候刚好时间片到了,也是很正常的。

双检锁【其实这个地方叫做 带锁的双检懒汉式单利模式】

既然懒汉式是非线程安全的,那就要改进它。最直接的想法是,给getInstance方法加锁不就好了,但是我们不需要给方法全部加锁啊,只需要给方法的一部分加锁就好了。

双检的目的是为了提高效率,当第一次线程创建了实例对象后,后边进入的线程通过判断第一个是否为null,可以直接不用走入加锁的代码区;

基于这个考虑,引入了双检锁(Double Check Lock,简称DCL)的写法:

public classDoubleCheckLockSingleton

{private static DoubleCheckLockSingleton instance = null;privateDoubleCheckLockSingleton()

{

}public staticDoubleCheckLockSingleton getInstance()

{if (instance == null)

{synchronized (DoubleCheckLockSingleton.class)

{if (instance == null)

instance= newDoubleCheckLockSingleton();

}

}returninstance;

}

}

双检锁的写法是不是线程安全的呢?是的,至于为什么,不妨以分析懒汉式写法的方式分析一下双检锁的写法。

线程A初次调用DoubleCheckLockSingleton.getInstance()方法,走12行,判断instance为null,进入同步代码块,此时线程切换到线程B,线程B调用DoubleCheckLockSingleton.getInstance()方法,由于同步代码块外面的代码还是异步执行的,所以线程B走12行,判断instance为null,等待锁。结果就是线程A实例化出了一个DoubleCheckLockSingleton,释放锁,线程B获得锁进入同步代码块,判断此时instance不为null了,并不实例化DoubleCheckLockSingleton。这样,单例类就保证了在内存中只存在一份。

单例模式在Java中的应用及解读

Runtime是一个典型的例子,看下JDK API对于这个类的解释"每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接,可以通过getRuntime方法获取当前运行时。应用程序不能创建自己的Runtime类实例。",这段话,有两点很重要:

1、每个应用程序都有一个Runtime类实例

2、应用程序不能创建自己的Runtime类实例

只有一个、不能自己创建,是不是典型的单例模式?看一下,Runtime类的写法:

f2940af480e1b4b65ede0eee02de2ab9.png

public class Runtime {

private static Runtime currentRuntime = new Runtime(); //使用饿汉式

/**

* Returns the runtime object associated with the current Java application.

* Most of the methods of class Runtime are instance

* methods and must be invoked with respect to the current runtime object.

*

* @return the Runtime object associated with the current

* Java application.

*/

public static Runtime getRuntime() {

return currentRuntime;

}

/** Don‘t let anyone else instantiate this class */

private Runtime() {}

...

}

f2940af480e1b4b65ede0eee02de2ab9.png

后面的就不黏贴了,到这里已经足够了,看到Runtime使用getRuntime()方法并让构造方法私有保证程序中只有一个Runtime实例且Runtime实例不可以被用户创建。

单例模式的好处

作为一种重要的设计模式,单例模式的好处有:

1、控制资源的使用,通过线程同步来控制资源的并发访问

2、控制实例的产生,以达到节约资源的目的

3、控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/529851.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

esp8266接7735_基于8266的ESPEASY固件接入HASS的教程(可无脑接入各类传感...

首先国际惯例,先放上成果:QQ图片20170629160143.png (172.48 KB, 下载次数: 3)2017-6-29 16:03 上传如上图所示,楼主把颗粒物传感器和二氧化碳传感器加入到了HASS里,当然,论坛之前也有诸位大神提供过类似固件和方法来实现这一目标…

java定义private_java9开始——接口中可以定义private私有方法

在传统的Java编程中,被广为人知的一个知识点是:java Interface接口中不能定义private私有方法。只允许我们定义public访问权限的方法、抽象方法或静态方法。但是从Java 9 开始,Interface 接口中允许定义私有方法和私有静态方法。下面我们就来…

java poi生成excel文件_java poi 导出Excel文件

1,导包 poi-3.9-XXX.JAR2, 创建一个实体对象public class Student implements Serializable {/****/private static final long serialVersionUID 1L;private int id;private String name;private int age;private Date borth;public Student(int id, String name…

java中捕获异常的作用_在Java中捕获通用异常?

您可以传递Class对象并以编程方式检查。public static void checkForException(String message,Class exceptionType, ExpectedExceptionBlock block) {try {block.exceptionThrowingCode();} catch (Exception ex) {if ( exceptionType.isInstance(ex) ) {return;} else {thro…

java如何循环调用方法_Java:调用方法的“中断”循环?

我的小程序有点问题。我有一个JOptionPane要求一个数字,如果该数字小于10,则一个循环会一直持续下去,并永远做下去,继续询问数字。 在该循环内,我调用一个方法,将int作为参数。 在该方法中,我需…

随机投点法计算定积分java_11 随机模拟积分 | 统计计算

11.4 高维定积分上面的两种计算一元函数定积分的方法可以很容易地推广到多元函数定积分,或称高维定积分。设\(d\)元函数\(h(x_1, x_2, \dots, x_d)\)定义于超矩形\[\begin{aligned}C \{(x_1, x_2, \ldots, x_d): a_i \leq x_i \leq b_i, i1,2,\ldots,d \}\end{alig…

java el ognl_EL和OGNL表达式的区分

OGNL是通常要结合Struts 2的标志一起使用,如 struts页面中不能单独使用,el可以单独使用 ${sessionScope.username}页面取值区别:名称servletognl elparametersre…

java query包,有没有Java的http_build_query函数的Java等价物?

I have a Map with my data and want to build a query string with it, just like I would with http_build_query on PHP. Im not sure if this code is the best implementation of it or if Im forgetting something?public String toQueryString(Map, ?> data) throw…

JAVA不同类型数组重载_java学习笔记--java中的方法与数组

方法完成特定功能的代码块方法的格式修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2...){//方法体return 返回值;}方法的调用方式通过方法名调用方法根据形式参数列表将实际参数传递给方法定义方法的注意事项1.方法必须定义在类中2.方法与…

链表每k个反转 java_K 个一组翻转链表

leetcode第25题(困难)问题描述给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。示例:给…

java里面的scanner怎么关闭_作业。scanner怎么不能关闭

package try_catch; import java.util.Scanner; public class TryCatchPractice2 {//在类开始声明,则其他方法都能调用 Scanner in=new Scanner(System.in); NoBookException NoB=new NoBookException(); String[] books={"语文","数学","英语"…

java ddd 领域事件_Cribbb基于DDD/Domain Event领域事件的开源PHP通知系统

Cribbb是一个使用DDD聚合根和领域事件Domain Events概念开发的PHP开源通知框架:cribbb/cribbb GitHub几乎所有Web应用都有一个通知提醒系统,这些通知系统都有共有的属性和功能:一个发往用户的消息管道Cribbb通知系统扮演一种消息管道&#x…

java 自带导出excel_4.java项目页面导出excel功能

用的是SSM框架,字段根据自己的业务需求改1.前台页面导出/*导出按钮提交*/function downloadExcel(){$("#dynamicDownload").submit();}2.后台相关代码import org.apache.poi.hssf.usermodel.HSSFCellStyle;import org.apache.poi.hssf.usermodel.HSSFFont;import org…

php 运行外部程序_PHP在linux上执行外部命令的方法

目录:一、PHP中调用外部命令介绍二、关于安全问题三、关于超时问题四、关于PHP运行linux环境中命令出现的问题一、PHP中调用外部命令介绍在PHP中调用外部命令,可以用,1>调用专门函数、2>反引号、3>popen()函数打开进程,三…

php直播pk规则,直播源码中的主播PK功能是如何实现的

直播行业为赢得更广泛用户的青睐,自然要不断开发更有趣的玩法、模式,在直播源码中加入主播PK功能就是一种提高直播互动性、激发用户好胜心的方法,一方面这种方法可以吸引更多用户观看,增加主播的曝光率,另一方面它又能…

php中手机端ajax上拉加载更多,jQuery手机网页上拉加载更多

手机网页和PC网页都可以使用的上拉加载更多内容,其中LoadingDataFn自己改为ajax加载就可以了var page 1, //分页码off_on false, //分页开关(滚动加载方法 1 中用的)timers null; //定时器(滚动加载方法 2 中用的)//加载数据var LoadingDataFn function() {var …

phpcms上传php,phpcms如何上传视频

phpcms如何上传视频?phpcms-v9上传视频文件时的解决方案1.不建议直接在后台上传视频文件,因为视频文件一般都比较大,直接上传影响带宽;可先通过ftp工具将视频文件上传到指定目录,然后再后台引入视频文件的地址即可2.如…

护卫神怎么重启php,护卫神·主机大师如何开启php_opcache_护卫神

护卫神主机大师支持5.5至7.3这几个版本开启php_opcache扩展。一,先打开护卫神主机大师面板-常用操作-打开软件目录二,打开phpweb目录,找到要开启opcache的php版本,比如我这里要在php5.5中开启,进入php55目录&#xff0…

php 首页加背景图片,如何在页首添加一张背景图片

Navy主题如何在页首添加一张图片可以http://www.ikk.me/这样子顶部添加背景图片他的代码是【点击查看】回复内容:Navy主题如何在页首添加一张图片可以http://www.ikk.me/这样子顶部添加背景图片他的代码是【点击查看】看了下代码,就是给 section 加了个 …

php装箱,php兑现装箱算法

php实现装箱算法贪婪法是一种不追求最优解,只希望得到较为满意解的方法。贪婪法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况&…