java基础--单例模式的7种实现【转载】
转载:http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html
第一种,线程不安全(懒汉模式)
1 public class Singleton1 {
2 private static Singleton1 instance;
3 private Singleton1(){}
4 public static Singleton1 getInstance(){
5 if(instance == null){
6 instance = new Singleton1();
7 }
8 return instance;
9 }
10 }
lazy loading,但是多线程不安全。不推荐。
第二种,线程安全(懒汉模式)
1 public class Singleton2 {
2 private static Singleton2 instance;
3 private Singleton2(){}
4 public static synchronized Singleton2 getInstance(){
5 if(instance == null){
6 instance = new Singleton2();
7 }
8 return instance;
9 }
10 }
lazy loading,线程安全,但是效率极其低下,同步锁锁的是对象,每次取对象都有加锁,因此不推荐,性能很低。
第三种,线程安全(饿汉模式)
1 public class Singleton3 {
2 private static Singleton3 instance = new Singleton3();
3 private Singleton3(){}
4 public static synchronized Singleton3 getInstance(){
5 return instance;
6 }
7 }
这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,这时候初始化instance显然没有达到lazy loading的效果。不推荐。
第四种,线程安全(饿汉模式)
public class Singleton4 {
private static Singleton4 instance ;
static {
instance = new Singleton4();
}
private Singleton4(){}
public static synchronized Singleton4 getInstance(){
return instance;
}
}
等同于第三种
第五种,线程安全(静态内部类)
public class Singleton5 {
private Singleton5(){}
public static synchronized Singleton5 getInstance(){
return SingletonHolder.instance;
}
private static class SingletonHolder{
private static Singleton5 instance = new Singleton5();
}
}
这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。
第六种,线程安全(枚举类)
public enum Singleton6 {
INSTANCE;
public void whateverMethod(){}
}
这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,推荐!
第七种,线程安全(双重校验模式)
public class Singleton7 {
private static Singleton7 instance;
private Singleton7(){}
public static synchronized Singleton7 getInstance(){
if(instance == null){
synchronized (Singleton7.class){
if(instance ==null){
instance = new Singleton7();
}
}
}
return instance;
}
}
最常用的一种。
总结
有两个问题需要注意:
1、如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类 装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。
2、如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。
对第一个问题修复的办法是:
private static Class getClass(String classname) throws ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null)
classLoader = Singleton.class.getClassLoader();
return (classLoader.loadClass(classname));
}
对第二个问题修复的办法是:
重写readResolve()方法。防止反序列化获取多个对象的漏洞。
无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。 实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。
java基础--单例模式的7种实现【转载】的更多相关文章
- Java:单例模式的七种写法(转载)
第一种(懒汉,线程不安全): package Singleton; /** * @echo 2013-10-10 懒汉 线程不安全 */ public class Singleton1 { priva ...
- JAVA实现单例模式的四种方法和一些特点
JAVA实现单例模式的四种方法和一些特点,需要的朋友可以参考一下 一.饿汉式单例类 复制代码 代码如下: public class Singleton { private Sing ...
- JAVA中单例模式的几种实现方式
1 线程不安全的实现方法 首先介绍java中最基本的单例模式实现方式,我们可以在一些初级的java书中看到.这种实现方法不是线程安全的,所以在项目实践中如果涉及到线程安全就不会使用这种方式.但是如果不 ...
- 【java基础 13】两种方法判断hashmap中是否形成环形链表
导读:额,我介绍的这两种方法,有点蠢啊,小打小闹的那种,后来我查了查资料,别人都起了好高大上的名字,不过,本篇博客,我还是用何下下的风格来写.两种方法,一种是丢手绢法,另外一种,是迷路法. 这两种方法 ...
- Java基础-synchronized关键字的用法(转载)
synchronized--同步 顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 当synchronized修饰 this或者非静态方法或者是一个实例的时候,所同步的锁是加在 ...
- java实现定时任务的三种方法 - 转载
java实现定时任务的三种方法 /** * 普通thread * 这是最常见的,创建一个thread,然后让它在while循环里一直运行着, * 通过sleep方法来达到定时任务的效果.这样可以快速简 ...
- Java基础12 类型转换与多态(转载)
类型检查 Java的任意变量和引用经过类型声明(type declaration),才能使用.我们之前见过对象数据.类数据.方法参数.方法返回值以及方法内部的自动变量,它们都需要声明其类型.Java是 ...
- Java:单例模式的七种写法
第一种(懒汉,线程不安全): 1 public class Singleton { 2 private static Singleton instance; 3 private Singleton ( ...
- Java:单例模式的七种写法[转]
第一种(懒汉,线程不安全): 1 public class Singleton { 2 private static Singleton instance; 3 privat ...
随机推荐
- PHPStorm开启MiniMap功能
Sublime Text 右侧的代码导航(MiniMap)功能相当好用,PHPStorm第三方插件,可以实现相同功能. 只需要下载 CodeGlance 插件即可,如下操作
- sqlite3中 timestamp使用
timestamp使用 一. timestamp两种属性:自动初始化: 此行为只在第一次写入数据时,怎么把时间设为当前时间. (DEFAULT CURRENT_TIMESTAMP)自动更新: 此行为在 ...
- Maven项目构建利器01——为什么要使用Maven
1.为什么要使用Maven a)一个项目就是一个工程 如果一个项目非常庞大,不适合用package(包)来划分模块, 最好是每一个模块对应一个工程 分工合作,借助于Maven就可以将一个项目拆分成多个 ...
- PHP的htmlspecialchars、strip_tags、addslashes
PHP的htmlspecialchars.strip_tags.addslashes是网页程序开发中常见的函数,今天就来详细讲述这些函数的用法: 1.函数strip_tags:去掉 HTML 及 PH ...
- Java引用与C语言指针的区别
1.现象 指针在运行时可以改变其所指向的值(地址)即指向其它变量,而引用一旦和某个对象绑定后就不能再改变,总是指向最初的对象. 2.编译 程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变 ...
- [易学易懂系列|rustlang语言|零基础|快速入门|(3)|所有权Ownership]
今天我们来讲讲rust最难,也是最重要的概念: Ownership,Borrowing,Lifetimes 首先我们来看看:ownership(所有权) 我们来看看下面的代码: let a = [1, ...
- IDEA部署Spring-boot到Docker容器
一.准备工作 idea安装Docker插件 centos7系统安装docker 二.打开docker远程端口 1. 编辑docker.service文件 vim /usr/lib/systemd/sy ...
- 如何编写高质量的js代码--底层原理
转自: 如何编写高质量的 JS 函数(1) -- 敲山震虎篇 本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/7lCK9cHmunvYlbm ...
- github readme 添加图片预览
 ![图片加载失败的时候就会显示这段话]( ...
- CentOS源码编译安装MySQL 5.5.15
CentOS源码编译安装MySQL 5.5.15 文章目录 [隐藏] 安装编译工具 下载源码 安装cmake和bison 编译安装MySQL 一些相关设置 安装编译工具 yum install g ...