美国上市公司,专注Java培训21年

Java中的模式--单态


单态定义:

Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。

Singleton模式就为我们提供了这样实现的可能。使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection)。

使用Singleton注意事项:

有时在某些情况下,使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器,跨JVM的

单态模式的演化:

单态模式是个简单的模式,但是这个简单的模式也有很多复杂的东西。

(注意:在这里补充一下,现在单态模式其实有一个写法是不错的见这里:#/dreamstone/archive/2007/02/27/101000.html,但还是建议看完这篇文章,因为解释的事情是不一样的,这里说的是为什么double-checked不能使用.)

一,首先最简单的单态模式,单态模式1

import java.util.*;

class Singleton

{

private static Singleton instance;

private Vector v;

private boolean inUse;

private Singleton()

{

v = new Vector();

v.addElement(new Object());

inUse = true;

}

public static Singleton getInstance()

{

if (instance == null) //1

instance = new Singleton(); //2

return instance; //3

}

}

这个单态模式是不安全的,为什么说呢 ?因为没考虑多线程,如下情况

Thread 1 调用getInstance() 方法,并且判断instance是null,然後进入if模块,

在实例化instance之前,

Thread 2抢占了Thread 1的cpu

Thread 2 调用getInstance() 方法,并且判断instance是null,然後进入if模块,

Thread 2 实例化instance 完成,返回

Thread 1 再次实例化instance

这个单态已经不在是单态

二,为了解决刚才的问题:单态模式2

public static synchronized Singleton getInstance()

{

if (instance == null) //1

instance = new Singleton(); //2

return instance; //3

}

采用同步来解决,这种方式解决了问题,但是仔细分析正常的情况下只有第一次时候,进入对象的实例化,须要同步,其它时候都是直接返回已经实例化好的instance不须要同步,大家都知到在一个多线程的程序中,如果同步的消耗是很大的,很容易造成瓶颈

三,为了解决上边的问题:单态模式3,加入同步

public static Singleton getInstance()

{

if (instance == null)

{

synchronized(Singleton.class) {

instance = new Singleton();

}

}

return instance;

}

同步改成块同步,而不使用函数同步,但是仔细分析,

又回到了模式一的状态,再多线程的时候根本没有解决问题

四,为了对应上边的问题:单态模式4,也就是很多人采用的Double-checked locking

public static Singleton getInstance()

{

if (instance == null)

{

synchronized(Singleton.class) { //1

if (instance == null) //2

instance = new Singleton(); //3

}

}

return instance;

}

这样,模式一中提到的问题解决了。不会出现多次实例化的现象

当第一次进入的时候,保正实例化时候的单态,在实例化后,多线程访问的时候直接返回,不须要进入同步模块,既实现了单态,又没有损失性能。表面上看我们的问题解决了,但是再仔细分析:

我们来假象这中情况:

Thread 1 :进入到//3位置,执行new Singleton(),但是在构造函数刚刚开始的时候被Thread2抢占cpu

Thread 2 :进入getInstance(),判断instance不等于null,返回instance,

(instance已经被new,已经分配了内存空间,但是没有初始化数据)

Thread 2 :利用返回的instance做某些操做,失败或者异常

Thread 1 :取得cpu初始化完成

过程中可能有多个线程取到了没有完成的实例,医学期刊并用这个实例作出某些操做。

-----------------------------------------

出现以上的问题是因为

mem = allocate(); //分配内存

instance = mem; //标记instance非空

//未执行构造函数,thread 2从这里进入

ctorSingleton(instance); //执行构造函数

//返回instance


【免责声明】本文部分系转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,如涉及作品内容、版权和其它问题,请在30日内与我们联系,我们会予以重改或删除相关文章,以保证您的权益!

Java开发高端课程免费试学

大咖讲师+项目实战全面提升你的职场竞争力

  • 海量实战教程
  • 1V1答疑解惑
  • 行业动态分析
  • 大神学习路径图

相关推荐

更多
  • java中的模型与渲染器
  • log4j详细配置必看
    log4j详细配置必看
    很多屌丝都觉得log4j不好用,因为它不输出到IDE的控制台,哈哈,其实都是配置惹的祸,下面看我怎么一步步配置到控制台的, 详情>>

    2015-01-06

  • Java创建线程的两个方法
    Java创建线程的两个方法
    Java提供了线程类Thread来创建多线程的程序。其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象。 详情>>

    2015-01-07

  • Java中的模式--单态
  • Java开班时间

    收起