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 的开源实现 ...
随机推荐
- CSS——伪元素与伪类
伪类与伪元素 伪类:在特殊性中占据0,0,1,0 :link 向未访问的链接添加特殊的样式.也就是说,链接所指的 URI 尚未出现在用户代理的历史中.这种状态与 :visited状态是互斥的. :vi ...
- Java设计模式之策略模式(一)
今年寒假没有回家,打算利用这个假期的时间进行学习设计模式,这一个人感觉比较牛的知识,前一段时间一直在忙着搞自己的专业课,还有就是捣鼓了一下Linux系统,没有好好的学习关于Java还有Android方 ...
- Android_gridView_LIstener_examle
layout.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" x ...
- Java读取一个文件并打印到控制台上
package test9; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundExcept ...
- 【转】java.util.vector中的vector的详细用法
[转]java.util.vector中的vector的详细用法 ArrayList会比Vector快,他是非同步的,如果设计涉及到多线程,还是用Vector比较好一些 import java.uti ...
- 转载:flash 跨域 crossdomain.xml
转载自http://hi.baidu.com/bozz_/item/e8b1c7c4ca31317489ad9e91 flash 跨域 crossdomain.xml 一.概述 位于www.cross ...
- Apache Rewrite url重定向功能的简单配置
http://www.jb51.net/article/24435.htm 1.Apache Rewrite的主要功能 就是实现URL的跳转和隐藏真实地址,基于Perl语言的正则表达式规范.平时帮助我 ...
- Oracle连接配置以及实例的备份和恢复
背景:一个团队项目开发,不可能每个人都架设自己本地的数据库,大多数情况下是统一用服务器上的数据库,这时候就需要进行远程数据库的连接.而且有时候还需要进行数据库搬迁 ,这时候就需要进行数据库的备份和恢复 ...
- C#变量初始化问题:字段初始值无法引用非静态字段、方法或属性
http://www.cnblogs.com/bluestorm/p/3432190.html 问题:字段初始值设定项无法引用非静态字段.方法或属性的问题 下面代码出错的原因,在类中定义的字段为什么不 ...
- asp.net 备份和恢复数据库
观看了Insus的视频写下来的,代码可能有点冗长,如有好的想法的,可以多交流. 前台: <form id="form1" runat="server"&g ...