java中哪些对象都是java单例模式的好处

在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
假设我2个线程同时对某个单例模式生成的对象进行操作,也就是操作的是同一个对象,那岂不是会造成此对象内部状态的不一致?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
单例模式必然伴随着多线程问题,你可以采用适当的锁机制来控制啊,或者ThreadLocal也是一种解决方案,具体问题具体分析,当然如果是无状态的类,就不用考虑这么多了。
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:博客分类:
单例模式属于对象创建型模式,其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点。对一些类来说,只有一个实例是很重要的,虽然系统中可以有许多打印机,但却只应该有一个打印机假脱机,只应该有一个文件系统和一个窗口管理器,一个数字滤波器只能有一个A/D转换器,一个会计系统只能专用于一个公司。怎样才能保证一个类只有一个实例并且这个实例易于被访问,一个全局变量使得一个对象可以被访问,但它不能防止你实例化多个对象,一个更好的方法是让类自身负责保存他的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法,这就是Singleton模式。
单例模式的要点  
一是某个类只能有一个实例;
二是它必须自行创建这个实例;
三是它必须自行向整个系统提供这个实例。
实用性:在下面的情况下可以使用Singleton模式。
l 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
l 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
从上面的类图中可以看出,在单例类中有一个构造函数 ,
但是这个构造函数却是私有的(前面是符号),
然后在里面还公开了一个 ()方法,
通过上面的类图不难看出单例模式的特点,从而也可以给出单例模式的定义:单例模式保证一个类仅有一个实例,同时这个类还必须提供一个访问该类的全局访问点。
下面来自:
单例模式根据实例化对象时机的不同分为两种:一种是饿汉式单例,一种是懒汉式单例。饿汉式单例在单例类被加载时候,就实例化一个对象交给自己的引用;而懒汉式在调用取得实例方法的时候才会实例化对象。代码如下:
饿汉式单例
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
懒汉式单例
[html] view plaincopy
public class Singleton {
private static S
private Singleton(){}
public static synchronized Singleton getInstance(){
if(singleton==null){
singleton = new Singleton();
单例模式的优点:
· 在内存中只有一个对象,节省内存空间。
· 避免频繁的创建销毁对象,可以提高性能。
· 避免对共享资源的多重占用。
· 可以全局访问。
适用场景:由于单例模式的以上优点,所以是编程中用的比较多的一种设计模式。我总结了一下我所知道的适合使用单例模式的场景:
· 需要频繁实例化然后销毁的对象。
· 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
· 有状态的工具类对象。
· 频繁访问数据库或文件的对象。
· 以及其他我没用过的所有要求只有一个对象的场景。
单例模式注意事项:
· 只能使用单例类提供的方法得到单例对象,不要使用反射,否则将会实例化一个新对象。
· 不要做断开单例类对象与类中静态引用的危险操作。
· 多线程使用单例使用共享资源时,注意线程安全问题。
关于java中单例模式的一些争议:
单例模式的对象长时间不用会被jvm垃圾收集器收集吗
看到不少资料中说:如果一个单例对象在内存中长久不用,会被jvm认为是一个垃圾,在执行垃圾收集的时候会被清理掉。对此这个说法,笔者持怀疑态度,笔者本人的观点是:在hotspot虚拟机1.6版本中,除非人为地断开单例中静态引用到单例对象的联接,否则jvm垃圾收集器是不会回收单例对象的。
对于这个争议,笔者单独写了一篇文章进行讨论,如果您有不同的观点或者有过这方面的经历请进入文章参与讨论。
在一个jvm中会出现多个单例吗
在分布式系统、多个类加载器、以及序列化的的情况下,会产生多个单例,这一点是无庸置疑的。那么在同一个jvm中,会不会产生单例呢?使用单例提供的getInstance()方法只能得到同一个单例,除非是使用反射方式,将会得到新的单例。代码如下
Class c = Class.forName(Singleton.class.getName());
Constructor ct = c.getDeclaredConstructor();
ct.setAccessible(true);
Singleton singleton = (Singleton)ct.newInstance();
这样,每次运行都会产生新的单例对象。所以运用单例模式时,一定注意不要使用反射产生新的单例对象。
懒汉式单例线程安全吗
主要是网上的一些说法,懒汉式的单例模式是线程不安全的,即使是在实例化对象的方法上加synchronized关键字,也依然是危险的,但是笔者经过编码测试,发现加synchronized关键字修饰后,虽然对性能有部分影响,但是却是线程安全的,并不会产生实例化多个对象的情况。
单例模式只有饿汉式和懒汉式两种吗
饿汉式单例和懒汉式单例只是两种比较主流和常用的单例模式方法,从理论上讲,任何可以实现一个类只有一个实例的设计模式,都可以称为单例模式。
单例类可以被继承吗
饿汉式单例和懒汉式单例由于构造方法是private的,所以他们都是不可继承的,但是其他很多单例模式是可以继承的,例如登记式单例。
饿汉式单例好还是懒汉式单例好
在java中,饿汉式单例要优于懒汉式单例。C++中则一般使用懒汉式单例。
单例模式比较简单,在此就不举例代码演示了。
更多信息请查看
浏览: 92333 次
你好, 关于 JDK 7中也有一个支持协程方式的实现 在那呀? ...
有道理,可恶,可恨。
你是一个会思考的人,前途无量,代码审查显然不能以风格和规则为主 ...
遇到过一模一样的问题
写出让计算机读懂的代码很容易,写出让人读懂的只有高手才能做到. ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'Java单例模式的三种情况
作为对象的创建模式[GOF95], 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。
  注:本文乃阎宏博士的《Java与模式》一书的第十五章。
  单例模式的要点
  单例单例
  显然单例模式的要点有三个;一是某各类只能有一个实例;二是它必须自行创建这个事例;三是它必须自行向整个系统提供这个实例。在下面的对象图中,有一个&单例对象&,而&客户甲&、&客户乙& 和&客户丙&是单例对象的三个客户对象。可以看到,所有的客户对象共享一个单例对象。而且从单例对象到自身的连接线可以看出,单例对象持有对自己的引用。
  资源管理
  一些资源管理器常常设计成单例模式。
  在计算机系统中,需要管理的资源包括软件外部资源,譬如每台计算机可以有若干个打印机,但只能有一个Printer Spooler, 以避免两个打印作业同时输出到打印机中。每台计算机可以有若干传真卡,但是只应该有一个软件负责管理传真卡,以避免出现两份传真作业同时传到传真卡中的情况。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。
  需要管理的资源包括软件内部资源,譬如,大多数的软件都有一个(甚至多个)属性(properties)文件存放系统配置。这样的系统应当由一个对象来管理一个属性文件。
  需要管理的软件内部资源也包括譬如负责记录网站来访人数的部件,记录软件系统内部事件、出错信息的部件,或是对系统的表现进行检查的部件等。这些部件都必须集中管理,不可政出多头。
  这些资源管理器构件必须只有一个实例,这是其一;它们必须自行初始化,这是其二;允许整个系统访问自己这是其三。因此,它们都满足单例模式的条件,是单例模式的应用。
  一个例子:Windows 回收站
  Windows 9x 以后的视窗系统中都有一个回收站,下图就显示了Windows 2000 的回收站。
  在整个视窗系统中,回收站只能有一个实例,整个系统都使用这个惟一的实例,而且回收站自行提供自己的实例。因此,回收站是单例模式的应用。
  双重检查成例
  在本章最后的附录里研究了双重检查成例。双重检查成例与单例模式并无直接的关系,但是由于很多C 语言设计师在单例模式里面使用双重检查成例,所以这一做法也被很多Java 设计师所模仿。因此,本书在附录里提醒读者,双重检查成例在Java 语言里并不能成立,详情请见本章的附录。
单例模式的结构
  单例模式有以下的特点:
   .. 单例类只可有一个实例。
   .. 单例类必须自己创建自己这惟一的实例。
   .. 单例类必须给所有其他对象提供这一实例。
  虽然单例模式中的单例类被限定只能有一个实例,但是单例模式和单例类可以很容易被推广到任意且有限多个实例的情况,这时候称它为多例模式(Multiton Pattern) 和多例类(Multiton Class),请见&专题:多例(Multiton )模式与多语言支持&一章。单例类的简略类图如下所示。
  由于Java 语言的特点,使得单例模式在Java 语言的实现上有自己的特点。这些特点主要表现在单例类如何将自己实例化上。
饿汉式单例类
  饿汉式单例类是在Java 语言里实现得最为简便的单例类,下面所示的类图描述了一个饿汉式单例类的典型实现。
  从图中可以看出,此类已经自已将自己实例化。
  代码清单1:饿汉式单例类
public class EagerSingleton
private static final EagerSingleton m_instance =
new EagerSingleton();
* 私有的默认构造子
private EagerSingleton() { }
* 静态工厂方法
public static EagerSingleton getInstance()
·224·Java 与模式
  读者可以看出,在这个类被加载时,静态变量m_instance 会被初始化,此时类的私有构造子会被调用。这时候,单例类的惟一实例就被创建出来了。
  Java 语言中单例类的一个最重要的特点是类的构造子类是私有的,从而避免外界利用构造子直接创建出任意多的实例。值得指出的是,由于构造子是私有的,因此,此类不能被继承。
  懒汉式单例类
  与饿汉式单例类相同之处是,类的构造子是私有的。与饿汉式单例类不同的是,懒汉式单例类在第一次被引用时将自己实例化。如果加载器是静态的,那么在懒汉式单例类被加载时不会将自己实例化。如下图所示,类图中给出了一个典型的饿汉式单例类实现。
  代码清单2:懒汉式单例类
package com.javapatterns.singleton.
public class LazySingleton
private static LazySingleton
m_instance =
* 私有的默认构造子,保证外界无法直接实例化
private LazySingleton() { }
* 静态工厂方法,返还此类的惟一实例
synchronized public static LazySingleton
getInstance()
if (m_instance == null)
m_instance = new LazySingleton();
  读者可能会注意到,在上面给出懒汉式单例类实现里对静态工厂方法使用了同步化,以处理多线程环境。有些设计师在这里建议使用所谓的&双重检查成例&。必须指出的是,&双重检查成例&不可以在Java 语言中使用。不十分熟悉的读者,可以看看后面给出的小节。
  同样,由于构造子是私有的,因此,此类不能被继承。饿汉式单例类在自己被加载时就将自己实例化。即便加载器是静态的,在饿汉式单例类被加载时仍会将自己实例化。单从资源利用效率角度来讲,这个比懒汉式单例类稍差些。
  从速度和反应时间角度来讲,则比懒汉式单例类稍好些。然而,懒汉式单例类在实例化时, 必须处理好在多个线程同时首次引用此类时的访问限制问题,特别是当单例类作为资源控制器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费时间。这意味着出现多线程同时首次引用此类的机率变得较大。
  饿汉式单例类可以在Java 语言内实现, 但不易在C++ 内实现,因为静态初始化在C++ 里没有固定的顺序,因而静态的m_instance 变量的初始化与类的加载顺序没有保证,可能会出问题。这就是为什么GoF 在提出单例类的概念时,举的例子是懒汉式的。他们的书影响之大,以致Java 语言中单例类的例子也大多是懒汉式的。实际上,本书认为饿汉式单例类更符合Java 语言本身的特点。
  登记式单例类
  登记式单例类是GoF 为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的。本书把他们的例子翻译为Java 语言,并将它自己实例化的方式从懒汉式改为饿汉式。只是它的子类实例化的方式只能是懒汉式的, 这是无法改变的。如下图所示是登记式单例类的一个例子,图中的关系线表明,此类已将自己实例化。
  代码清单3:登记式单例类
import java.util.HashM
public class RegSingleton
static private HashMap m_registry = new HashMap();
RegSingleton x = new RegSingleton();
m_registry.put( x.getClass().getName() , x);
* 保护的默认构造子
protected RegSingleton() {}
* 静态工厂方法,返还此类惟一的实例
static public RegSingleton getInstance(String name)
if (name == null)
name = &com.javapatterns.singleton.demos.RegSingleton&;
if (m_registry.get(name) == null)
m_registry.put( name,
Class.forName(name).newInstance() ) ;
catch(Exception e)
System.out.println(&Error happened.&);
return (RegSingleton) (m_registry.get(name) );
* 一个示意性的商业方法
public String about()
return &Hello, I am RegSingleton.&;
  它的子类RegSingletonChild 需要父类的帮助才能实例化。下图所示是登记式单例类子类的一个例子。图中的关系表明,此类是由父类将子类实例化的。
  下面是子类的源代码。
  代码清单4:登记式单例类的子类
import java.util.HashM
public class RegSingletonChild extends RegSingleton
public RegSingletonChild() {}
* 静态工厂方法
static public RegSingletonChild getInstance()
return (RegSingletonChild)
RegSingleton.getInstance(
&com.javapatterns.singleton.demos.RegSingletonChild& );
* 一个示意性的商业方法
public String about()
return &Hello, I am RegSingletonChild.&;
  在GoF 原始的例子中,并没有getInstance() 方法,这样得到子类必须调用的getInstance(String name)方法并传入子类的名字,因此很不方便。本章在登记式单例类子类的例子里,加入了getInstance() 方法,这样做的好处是RegSingletonChild 可以通过这个方法,返还自已的实例。而这样做的缺点是,由于数据类型不同,无法在RegSingleton 提供这样一个方法。由于子类必须允许父类以构造子调用产生实例,因此,它的构造子必须是公开的。这样一来,就等于允许了以这样方式产生实例而不在父类的登记中。这是登记式单例类的一个缺点。
  GoF 曾指出,由于父类的实例必须存在才可能有子类的实例,这在有些情况下是一个浪费。这是登记式单例类的另一个缺点。
深入解析单例模式:
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?其他回答(1)
和我犯的一样的错,告诉你它不是单例。因为getInstance()方法得到的对象要求是不同的对象。比如今天5点,明天3点。
园豆:9551
&&&您需要以后才能回答,未注册用户请先。

我要回帖

更多关于 java的单例模式 的文章

 

随机推荐