Java单实例的最佳写法
前言:
代码简洁与性能高效无法两全其美,本文章专注于大并发程序的性能,如果您追求代码简洁,本文章可能不太适合,因为本文章主要讨论如何写出在高并发下也能运行很好的代码。
并文章属于Java并发编程实战中例子。但结合实际场景进行了阐述。
通常,我们如果写一个单实例模式的对象,一般会这样写:
写法一:
- public class Singleton {
- private static final Singleton instance = new Singleton();
- /**
- * 防止其他人new对象
- */
- private Singleton(){
- System.out.println("init");
- }
- public static Singleton getInstance(){
- return instance;
- }
- }
这种方式叫饥饿式单实例,意思是说,不管你用不用这个类的方法,我都把这个类需要的一切资源都分配好。但这样写有一个问题,就是如果这类需要的资源比较多,在系统启动的时候,就会很慢。
因此要求有懒汉式单实例,于是就出现了第二中写法,
写法二:
- public class Singleton {
- private static Singleton instance = null;
- /**
- * 防止其他人new对象
- */
- private Singleton(){
- System.out.println("init");
- }
- public static Singleton getInstance(){
- if(instance == null){
- instance = new Singleton();
- }
- return instance;
- }
- }
这种方式叫懒汉式单实例,即通常所说的延迟加载。这样,在系统启动的时候,不会加载类所需要的各种资源,只有真正使用的时候才去加载各种资源。
但这种方法马上就可以看出问题,因为在多线程情况下,可能会导致重复初始化的问题(不明白这个道理,那您需要补充一下同步及多线程知识了)。于是有了改进版,即目前网上比较流行的写法。
写法三:
- public class Singleton {
- private static Singleton instance = null;
- /**
- * 防止其他人new对象
- */
- private Singleton(){
- System.out.println("init");
- }
- public static synchronized Singleton getInstance(){
- if(instance == null){
- instance = new Singleton();
- }
- return instance;
- }
- }
加上关键字synchronized,可以保证只有一个线程在执行这个方法。这个方法至此应该说是比较完美的了,但是,专家不这么认为,在高并发多线程的访问系统中,synchronized关键字会让程序的吞吐量急剧下降,因此,在高并发系统中,应该尽量避免使用synchronized锁。
但这并不能难住我们聪明的软件工程师,有人便写出了双重锁的程序。方法如下:
写法四:
这样,通常获得单实例引用是没有锁的,只有第一次初始化时才会加锁,而且如果多个线程进入临界区区后,理论上只有第一个进入临界区的线程才会初始化对象,之后进入临界区的线程因为之前的线程已经初始化,就不会再次进行初始化。
但专家怎么说呢?这个代码有问题。首先,这个程序对同步的应用很到位,即当进入synchronied区,只有一个线程在访问Singleton类。但却忽略了变量的可见性。因为在没有同步的保护下,instance的值在多个线程中可能都是空的,因为即便第一个线程对类进行了初始化,并把类的引用赋值给了instance变量,但也不能保证instance变量的值对其他线程是可见的,因为变量instance没有采用同步的机制。
在java5之后,可以在instance前面添加volatile关键字来解决这个问题,但是这种双重锁的方式已经不建议使用。
那么,看看大师推荐的写法吧,见 Java Concurrency In Practice的List 16.6代码:
写法五:
综上各种写法,发现写法一虽然在启动时会让系统启动的慢一些,但却不失为一种高效的写法,当然,如果确实对系统启动时的速度要求高的话,则应该考虑写法五了。
Java单实例的最佳写法的更多相关文章
- Java ,单实例 多线程 ,web容器,servlet与struts1-2.x系列,线程安全的解决
1.Servlet是如何处理多个请求同时访问呢? 回答:servlet是默认采用单实例,多线程的方式进行.只要webapp被发布到web容器中的时候,servlet只会在发布的时候实例化一次,serv ...
- Java中的单实例
前几天刚学完单实例设计模式,今天看代码时发现一行代码很奇怪,getRuntime()函数的返回类型怎么是它本身,忽然想起前几天学的单实例模式,于是找到方法的定义,果然是静态私有变量,获取实例的公有方法 ...
- 【java】单实例下的 流水号【21位】
单实例环境,不是分布式 需要流水号 /** * 流水号生成器 * * 年+天号+毫秒+随机数 * 2019+134+480+11位随机数 * 4+3+3+11 = 21位 * * * @author ...
- java单例模式的几种写法比较
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
- java单例-积木系列
一步步知识点归纳吧,把以前似懂非懂,了解表面,知道点不知道面的知识归一下档. 懒汉式单例: 私有化构造函数,阻止外界实例话对象,调用getInstance静态方法,判断是否已经实例化. 为什么是懒 ...
- Servlet单实例多线程模式
http://kakajw.iteye.com/blog/920839 前言:Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率.由于Servlet/JSP默认是以 ...
- 【Java学习笔记之三十】详解Java单例(Singleton)模式
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
- 转:java单例设计模式
本文转自:http://www.cnblogs.com/yinxiaoqiexuxing/p/5605338.html 单例设计模式 Singleton是一种创建型模式,指某个类采用Singleton ...
- zookeeper的单实例和伪集群部署
原文链接: http://gudaoyufu.com/?p=1395 zookeeper工作方式 ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现 ...
随机推荐
- chrome,firefox
chrome开发者工具 firefox插件httpfox
- IOS中如何显示带有html标签的富文本
NSString *strHTML = @"<p>你好</p><p> 这是一个例子,请显示</p><p>外加一个ta ...
- 深入理解计算机系统第二版习题解答CSAPP 2.16
填写下表,说明不同移位运算对单字节数的影响. x x<<3 x>>2(逻辑) x>>2(算术) 十六进制 二进制 二进制 十六进制 二进制 十六进制 二进制 十六进 ...
- Python 基础【第九篇】运算
Python的运算符比较通俗和其他语言的几乎没什么区别 一.算数运算符 " + " 加法运算 >>> 1+3 4 加法运算扩展 "增强赋值操作" ...
- linux系统下搭建自己的web服务器
之前在windows 2008 server上搭建了一个用于测试的web服务器,但是在打开网站的时候特别的慢,尤其是图片的加载都会失败,当时以为是路径的问题,但是在服务器上自己打开都特别慢,自己实在找 ...
- centos7下载安装谷歌浏览器
centos7安装完成结束后,发现自带的火狐浏览器不太习惯,自己还是习惯谷歌浏览器,因为是新手嘛,所以自己就各种找教程看如何下载安装谷歌浏览器,一个一个按照教程试验,终于最后试验成功了一个,亲测可用. ...
- js 简易判断一个数字是否是小数
参考:js验证输入是否是小数 我的方法是: //check the number is decimal number function checkDecimal(number){ if(!isNaN( ...
- android之TCP客户端框架
一.程序框架 1.1 创建方法 onCreate 1.1.1 创建连接按键线程,并使能线程(触发原因:可按键.其他操作,并进行状态判断): Connect_Thread connect_Thread ...
- 猪满满 购物APP
猪满满是专注“省钱,赚钱”的购物App,使用自定义tabar分为四大类,分别是首页,超返,发现,我的. 首页:使用UItableview,自定义cell展示商品. 超返:自定义Button分为综合,返 ...
- Sqlserver 理解子查询
理解子查询: 理解子查询: 多表连接查询往往也可以用子查询进行替代 子查询本质是嵌套进其他 select update insert Delete 语句的一个被限制的select语句,在子查询中,只有 ...