原文地址:http://blog.csdn.net/jason0539/article/details/23297037

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

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

  1. public class Singleton {
  2. private static Singleton uniqueInstance = null;
  3. private Singleton() {
  4. // Exists only to defeat instantiation.
  5. }
  6. public static Singleton getInstance() {
  7. if (uniqueInstance == null) {
  8. uniqueInstance = new Singleton();
  9. }
  10. return uniqueInstance;
  11. }
  12. // Other methods...
  13. }

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

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

  1. package jason.single;
  2. public class TestStream {
  3. String name = null;
  4. public String getName() {
  5. return name;
  6. }
  7. public void setName(String name) {
  8. this.name = name;
  9. }
  10. private TestStream() {
  11. }
  12. private static TestStream ts1 = null;
  13. public static TestStream getTest() {
  14. if (ts1 == null) {
  15. ts1 = new TestStream();
  16. }
  17. return ts1;
  18. }
  19. public void printInfo() {
  20. System.out.println("the name is " + name);
  21. }
  22. }
  1. package jason.single;
  2. public class TMain {
  3. public static void main(String[] args){
  4. TestStream ts1 = TestStream.getTest();
  5. ts1.setName("jason");
  6. TestStream ts2 = TestStream.getTest();
  7. ts2.setName("0539");
  8. ts1.printInfo();
  9. ts2.printInfo();
  10. if(ts1 == ts2){
  11. System.out.println("创建的是同一个实例");
  12. }else{
  13. System.out.println("创建的不是同一个实例");
  14. }
  15. }
  16. }

运行结果:

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

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. //懒汉式单例类.在第一次调用的时候实例化
  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. }
  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与模式》之单例模式(转载)的更多相关文章

  1. Java 序列化 序列化与单例模式 [ 转载 ]

    Java 序列化 序列化与单例模式 [ 转载 ] @author Hollis 本文将通过实例+阅读Java源码的方式介绍序列化是如何破坏单例模式的,以及如何避免序列化对单例的破坏. 单例模式,是设计 ...

  2. Java ------ 工厂模式、单例模式

    工厂模式 简单工厂模式: 1.创建Car接口 public interface Car { public void drive(); } 2.创建两个实体类,分别实现Car接口 public clas ...

  3. 《JAVA与模式》之单例模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述单例模式的: 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式的 ...

  4. Java中的GOF23(23中设计模式)--------- 单例模式(Singleton)

    Java中的GOF23(23中设计模式)--------- 单例模式(Singleton) 在Java这这门语言里面,它的优点在于它本身的可移植性上面,而要做到可移植的话,本身就需要一个中介作为翻译工 ...

  5. 《JAVA与模式》之单例模式 [转]

    在阎宏博士的<JAVA与模式>一书中开头是这样描述单例模式的: 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式的 ...

  6. Java设计模式(4)——创建型模式之单例模式(Singleton)

    一.概述 弥补一下之前没有给设计模式下的定义,先介绍一下设计模式(引用自百度百科): 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结. 使用设计 ...

  7. 《JAVA与模式》之观察者模式(转载)

    <JAVA与模式>之观察者模式(转载)  原文链接:http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html ...

  8. 资源池模式和单例模式实现的自定义数据库连接池java实现版

    在企业级开发中,我们往往不会直接使用原生的JDBC操作来实现与数据库得连接.因为数据库的连接是一个很宝贵的资源且耗时,我们往往会在内存中引入一个资源池来统一管理数据库的连接.这个模式也被总结为一种设计 ...

  9. java future模式 所线程实现异步调用(转载

    java future模式 所线程实现异步调用(转载) 在多线程交互的中2,经常有一个线程需要得到另个一线程的计算结果,我们常用的是Future异步模式来加以解决.Future顾名思意,有点像期货市场 ...

  10. 《JAVA与模式》之责任链模式 【转载】

    转载自java_my_life的博客 原文地址:http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html 在阎宏博士的&l ...

随机推荐

  1. nginx服务企业应用

    1.1 常用来提供静态服务的软件 Apache :这是中小型Web服务的主流,Web服务器中的老大哥, Nginx :大型网站Web服务的主流,曾经Web服务器中的初生牛犊,现已长大. Nginx 的 ...

  2. WIN10系统如何使用传统WIN7开始菜单

    安装StartlsBack 默认按WIN键就可以回到WIN7的菜单了 右击WIN可以点击属性,详细设置菜单样式

  3. SpringMVC框架使用注解执行定时任务(转)

    首先要配置我们的SpringMVC文件 xmlns 加下面的内容: xmlns:task="http://www.springframework.org/schema/task" ...

  4. 微信小程序 - ios不能播放背景音乐

    由以下原因导致的 1. 未设置标题(backgroundPlayer.title)或标题为空 2. url只能英文,不能出现空格以及其它字符(中文.韩文.日文等)- iOS要求英文路径

  5. JAVA各种泛型事例总结

    转自:http://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845938.html 普通泛型 class Point<T>{ // 此 ...

  6. Flex报错Error #2048: 安全沙箱冲突

    Flex+JPA架构,JPA程序迁移,从Aserver到B. 其它一切没变.唯一变的就是IP. 前端Flex也就是swf报错Error #2048: 安全沙箱冲突:http://xxx.swf 不能从 ...

  7. Centos 6下安装Oracle 11gR2

    一.安装环境 CentOS release 6.7 (Final) Oracle Database 11g Release 2 二.安装前准备 #修改主机名 修改/etc/sysconfig/netw ...

  8. C++11中的mutex, lock,condition variable实现分析

    本文分析的是llvm libc++的实现:http://libcxx.llvm.org/ C++11中的各种mutex, lock对象,实际上都是对posix的mutex,condition的封装.不 ...

  9. __set() __get() _isset() __unset() 在__unset() 在类中没有事先声明和已经声明过的属性调用unset的区别

    <?php //echo strtr("I Love Mysql, Love PHP", "Mysql","MYSQL"); //$a ...

  10. 微软的在线文档存储OneDrive使用帮助

    onedrive默认空间5G,对于一般的文档存储够用的,很方便不限速!!! ###官方介绍 https://support.office.com/zh-cn/article/%E4%BA%86%E8% ...