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 的开源实现 ...
随机推荐
- 基于动态库的C++插件开发模型
基类为抽象类,在不同的动态库中实现不同的执行行为,但是每个动态库要提供2个统一的方法:1) baseClass * create(); 2) void destroy( baseClass* );,调 ...
- 嵌入式中 MMU的功能
学习嵌入式才发现要看的书太多,外面的世界很精彩啊,现在来说说MMU吧,MMU是Memory Management Unit的缩写,是用来管理虚拟内存系统的器件. MMU通常是CPU的一部分,本身有少量 ...
- 怎样在CentOS 7.0上安装和配置VNC服务器
VNC轻松连接远程Linux桌面 http://jingyan.baidu.com/article/6c67b1d6f1bac92786bb1e6d.html 这是一个关于怎样在你的 CentOS 7 ...
- Agile.Net 组件式开发平台 - 开发环境部署
环境准备: Windows 7 (32/64) Windows Server 2008 (32/64) Microsoft SQL Server 2008 R2 (32/64) Microsoft V ...
- 对象创建型模式------Singleton(单例模式)
地址:http://blog.csdn.net/wuzhekai1985/article/details/6665869.仅供自己参考学习. 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局节 ...
- python学习第二天:数字与字符串转换及逻辑值
1.数字与字符串的转化 #1.数字转字符,使用格式化字符串: *1.demo = ‘%d’ % source *2.%d整型:%f 浮点型 :%e科学计数 ...
- 通过sql做数据透视表,数据库表行列转换(pivot和Unpivot用法)(一)
在mssql中大家都知道可以使用pivot来统计数据,实现像excel的透视表功能 一.MSsqlserver中我们通常的用法 1.Sqlserver数据库测试 ---创建测试表 Create tab ...
- bzoj 2734 [HNOI2012]集合选数 状压DP+预处理
这道题很神啊…… 神爆了…… 思路大家应该看别的博客已经知道了,但大部分用的插头DP.我加了预处理,没用插头DP,一行一行来,速度还挺快. #include <cstdio> #inclu ...
- OpenJudge/Poj 1661 帮助 Jimmy
1.链接地址: bailian.openjudge.cn/practice/1661 http://poj.org/problem?id=1661 2.题目: 总Time Limit: 1000ms ...
- js中的in-for循环
<!doctype html><html lang="en"> <head> <meta charset="UTF-8" ...