概念:
  java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
  单例模式有一下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。
  单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。

首先看一个经典的单例实现。

public class Singleton {

private static Singleton uniqueInstance = null;

private Singleton() {

// Exists only to defeat instantiation.

}

public static Singleton getInstance() {

if (uniqueInstance == null) {

uniqueInstance = new Singleton();

}

return uniqueInstance;

}

// Other methods...

}

Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)

但是以上实现没有考虑线程安全问题。所谓线程安全是指:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。显然以上实现并不满足线程安全的要求,在并发环境下很可能出现多个Singleton实例。

  1. 1 public class TestStream {
    2 private String name;
    3 public String getName() {
    4 return name;
    5 }
    6 public void setName(String name) {
    7 this.name = name;
    8 }
    9 //该类只能有一个实例
    10 private TestStream(){} //私有无参构造方法
    11 //该类必须自行创建
    12 //有2种方式
    13 /*private static final TestStream ts=new TestStream();*/
    14 private static TestStream ts1=null;
    15 //这个类必须自动向整个系统提供这个实例对象
    16 public static TestStream getTest(){
    17 if(ts1==null){
    18 ts1=new TestStream();
    19 }
    20 return ts1;
    21 }
    22 public void getInfo(){
    23 System.out.println("output message "+name);
    24 }
    25 }
  1. 1 public class TestMain {
    2 public static void main(String [] args){
    3 TestStream s=TestStream.getTest();
    4 s.setName("张孝祥");
    5 System.out.println(s.getName());
    6 TestStream s1=TestStream.getTest();
    7 s1.setName("张孝祥");
    8 System.out.println(s1.getName());
    9 s.getInfo();
    10 s1.getInfo();
    11 if(s==s1){
    12 System.out.println("创建的是同一个实例");
    13 }else if(s!=s1){
    14 System.out.println("创建的不是同一个实例");
    15 }else{
    16 System.out.println("application error");
    17 }
    18 }
    19 }

运行结果:
  张孝祥
  张孝祥
  output message 张孝祥
  output message 张孝祥
  创建的是同一个实例

结论:由结果可以得知单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。

1.饿汉式单例类

  1. 1 //饿汉式单例类.在类初始化时,已经自行实例化
    2 public class Singleton1 {
    3 //私有的默认构造子
    4 private Singleton1() {}
    5 //已经自行实例化
    6 private static final Singleton1 single = new Singleton1();
    7 //静态工厂方法
    8 public static Singleton1 getInstance() {
    9 return single;
    10 }
    11 }

2.懒汉式单例类

  1. 1 //懒汉式单例类.在第一次调用的时候实例化
    2 public class Singleton2 {
    3 //私有的默认构造子
    4 private Singleton2() {}
    5 //注意,这里没有final
    6 private static Singleton2 single=null;
    7 //静态工厂方法
    8 public synchronized static Singleton2 getInstance() {
    9 if (single == null) {
    10 single = new Singleton2();
    11 }
    12 return single;
    13 }
    14 }

3.登记式单例类

  1. 1 import java.util.HashMap;
    2 import java.util.Map;
    3 //登记式单例类.
    4 //类似Spring里面的方法,将类名注册,下次从里面直接获取。
    5 public class Singleton3 {
    6 private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();
    7 static{
    8 Singleton3 single = new Singleton3();
    9 map.put(single.getClass().getName(), single);
    10 }
    11 //保护的默认构造子
    12 protected Singleton3(){}
    13 //静态工厂方法,返还此类惟一的实例
    14 public static Singleton3 getInstance(String name) {
    15 if(name == null) {
    16 name = Singleton3.class.getName();
    17 System.out.println("name == null"+"--->name="+name);
    18 }
    19 if(map.get(name) == null) {
    20 try {
    21 map.put(name, (Singleton3) Class.forName(name).newInstance());
    22 } catch (InstantiationException e) {
    23 e.printStackTrace();
    24 } catch (IllegalAccessException e) {
    25 e.printStackTrace();
    26 } catch (ClassNotFoundException e) {
    27 e.printStackTrace();
    28 }
    29 }
    30 return map.get(name);
    31 }
    32 //一个示意性的商业方法
    33 public String about() {
    34 return "Hello, I am RegSingleton.";
    35 }
    36 public static void main(String[] args) {
    37 Singleton3 single3 = Singleton3.getInstance(null);
    38 System.out.println(single3.about());
    39 }
    40 }

学习Java的同学注意了!!! 
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:492139965 我们一起学Java!

Java 单例模式详解的更多相关文章

  1. 9种Java单例模式详解(推荐)

    单例模式的特点 一个类只允许产生一个实例化对象. 单例类构造方法私有化,不允许外部创建对象. 单例类向外提供静态方法,调用方法返回内部创建的实例化对象.  懒汉式(线程不安全) 其主要表现在单例类在外 ...

  2. 【JAVA单例模式详解】

    设计模式是一种思想,适合于任何一门面向对象的语言.共有23种设计模式. 单例设计模式所解决的问题就是:保证类的对象在内存中唯一. 举例: A.B类都想要操作配置文件信息Config.java,所以在方 ...

  3. Java 单例模式详解(转)

    概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. ...

  4. 9种Java单例模式详解

    单例模式的特点 一个类只允许产生一个实例化对象. 单例类构造方法私有化,不允许外部创建对象. 单例类向外提供静态方法,调用方法返回内部创建的实例化对象. 懒汉式(线程不安全) 其主要表现在单例类在外部 ...

  5. java单例模式详解

    饿汉法 饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建.代码如下: public class Singleton { private static Singleton = ne ...

  6. android java 设计模式详解 Demo

    android java 设计模式详解 最近看了一篇设计模式的文章,深得体会,在此基础我将每种设计模式的案例都写成Demo的形式,方便读者研究学习, 首先先将文章分享给大家: 设计模式(Design ...

  7. Java内部类详解

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

  8. 黑马----JAVA迭代器详解

    JAVA迭代器详解 1.Interable.Iterator和ListIterator 1)迭代器生成接口Interable,用于生成一个具体迭代器 public interface Iterable ...

  9. C++调用JAVA方法详解

    C++调用JAVA方法详解          博客分类: 本文主要参考http://tech.ccidnet.com/art/1081/20050413/237901_1.html 上的文章. C++ ...

随机推荐

  1. [原] KVM 虚拟化原理探究 —— 目录

    KVM 虚拟化原理探究 -- 目录 标签(空格分隔): KVM KVM 虚拟化原理探究(1)- overview KVM 虚拟化原理探究(2)- QEMU启动过程 KVM 虚拟化原理探究(3)- CP ...

  2. linux拷贝命令,移动命令

    http://blog.sina.com.cn/s/blog_7479f7990101089d.html

  3. APEX:对object中数据进行简单处理?

    在Salesforce中,常常要对各种数据进行处理,已满足业务逻辑.本篇文章会介绍如何实现从object获取数据,然后将取得的数据进行一系列简单处理. 第一步:SongName__c 是一个新建的ob ...

  4. 浏览器的兼容模式下的button中文字垂直方向不居中显示

    <button style="cursor:pointer;vertical-align: middle;" >删除</button> 这时候垂直不居中. ...

  5. Android中Fragment与Activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...

  6. Maven仓库搭建和配置

    maven在本地搭建仓库的实际需求maven在项目构建过程需要下载一些必要的软件包,这些默认的下载链接都是访问maven的远程中央仓库Central Repo.如果项目中的成员,每次第一次构建的时候都 ...

  7. Hadoop伪分布式集群环境搭建

    本教程讲述在单机环境下搭建Hadoop伪分布式集群环境,帮助初学者方便学习Hadoop相关知识. 首先安装Hadoop之前需要准备安装环境. 安装Centos6.5(64位).(操作系统再次不做过多描 ...

  8. 最近在玩linux时 yum 遇到了问题

    主要是软件源出现了问题 我做的方式可能比较粗暴 ls -l /etc/yum.repos.d/       /*查看软件源*/ rm -rf /etc/yum.repos.d/   /*全删了*/ m ...

  9. linux压缩和解压缩命令大全

    .tar 解包:tar zxvf FileName.tar 打包:tar czvf FileName.tar DirName ------------------------------------- ...

  10. .NET面试题系列[6] - 反射

    反射 - 定义,实例与优化 在面试中,通常会考察反射的定义(操作元数据),可以用反射做什么(获得程序集及其各个部件),反射有什么使用场景(ORM,序列化,反序列化,值类型比较等).如果答得好,还可能会 ...