A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 山水游客 中级黑马   /  2012-6-27 11:29  /  3631 人查看  /  13 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文



饿汉式:
class Single
{
private static Single s=new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}

懒汉式:
class Single
{
private static Single s=null;
private Single(){}
public static Single getInstance()
{
if(s==null)
s=new Single();
return s;
}
}
单例设计模式中的饿汉式和懒汉式在加载时有什么不同?为什么在java开发中一般使用饿汉式,不用懒汉式?

13 个回复

倒序浏览
饿汗式:顾名思义这个人很饥饿,一上来就先创建对象.先把对象拿到.
class Single
{
private static Single s=new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}

懒汉式:顾名思义这个人很懒.先给对象赋个空.谁用谁创建.创建了之后就不为空了.就不能再创建了.只能通过公共方法取得对象来了,确保对象唯一性.
class Single
{
private static Single s=null;
private Single(){}
public static Single getInstance()
{
if(s==null)
s=new Single();
return s;
}
}
懒汉式较常用把.今后结合多线程了之后你就清楚了.多个并发的获取同一个对象.

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
吴琼 发表于 2012-6-27 11:43
饿汗式:顾名思义这个人很饥饿,一上来就先创建对象.先把对象拿到.
class Single
{

童鞋 不管是什么式其实就是一个结果嘛……对象都是唯一的。因为他原本都是单例模式。个人认为懒汉式还是比较好的。
回复 使用道具 举报
朋友不要只是自己一门心思的看视频;抽点时间看看论坛;每天都有很多人提问的:这样可以从中找到很多自己学习的时候可能会犯而你还没有犯的错误;
这样学习的效率会高很多的;

/*
Single类一进内存,就已经创建好了对象。
class Single
{
        private static Single s = new Single();
        private Single(){}
        public static Single getInstance()
        {
                return s;
        }
}
这个是先初始化对象。
称为:饿汉式。
*/


class Single
{
        private static Single s = null;
        private Single(){}
        public static Single getInstance()
        {
                if(s==null)
                {
                        synchronized(Single.class)
                        {                                
                                if(s==null)
                                        s = new Single();
                        }
                }
                return s;
        }
}
//对象是方法被调用时,才初始化,也叫做对象的延时加载。成为:懒汉式。
//Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象.

//定义单例,建议使用饿汉式。懒汉式有安全隐患;要用到同步锁才能解除隐患;比较复杂;

class  
{
        public static void main(String[] args)
        {
                System.out.println("Hello World!");
        }
}

评分

参与人数 2技术分 +4 收起 理由
wangfayin + 3 赞一个!
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
所谓“懒汉式”与“饿汉式”的区别,是在与建立单例对象的时间不同。
“懒汉式”是在你真正用到的时候才去建这个单例对象:
比如:有个单例对象
     private static Student student = null;  //不建立对象
     Student getInstance(){
             if(student == null) {        //先判断是否为空
                student = new Student();  //懒汉式做法
             }
             return student;
          }

“饿汉式”是在不管你用的用不上,一开始就建立这个单例对象:
比如:有个单例对象
      private static Student student = new Student(); //建立对象
      Student getInstance(){
                return student;  //直接返回单例对象
          }

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
本帖最后由 陈淑飞 于 2012-6-27 12:16 编辑

为什么要用饿汉式?
1. 代码简单,容易理解。
   这个就不解释了,相对懒汉式来说,它简单多了。
2. 线程较安全。
  因为饿汉式, 一上来,类一加载链接,由于private static Single s=new Single();是静态的类变量所以就被实例化了。
  CPU是分时处理各个应用程序的, 所以看起来,多个应用程序都在处理执行。
  好像是8086 以前的CPU是不支持分时处理的,而80286 以上的CPU是支持分时处理的。 现在的服务器至少都是 至强 4核以上的了。
  所以都 支持 多分处理的。 特别是 HTTP 应用时。
  若多个人, 同时在请求时,特别是那个 秒杀 应用之类的, 同时点HTTP请求的得有 每个人 一个线程在 服务器处理。
  public static Single getInstance()
{
if(s==null)  //-------- Setp 1 当a 线程执行到此后, CPU分时 给b 线程处理,
s=new Single();   //--- Setp 2 b 线程此时 ,也进入了s==null 条件判断,发现是真的,也进了 if 语句里。
return s;  //---  最终不就导致了a、b 线程都 new 了一个对象了吗? 若是秒杀等应用,那不知道 被实例了多少次,还叫单列模式吗?
}
}

要解决这个问题,就要用到synchronized,等后面你学到多线程就了解了。

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
本帖最后由 周兴中 于 2012-6-27 12:25 编辑

饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变 ,所以,饿汉式无需关注多线程问题、写法简单明了、能用则用。但是它是加载类时创建实例,所以如果是一个工厂模式、缓存了很多实例、那么就得考虑效率问题,因为这个类一加载则把所有实例不管用不用一块创建。

懒汉式优点是延时加载、 是在需要的时候才创建对象。缺点是应该用同步。如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。对于所谓的懒汉式最好用双锁,不要把同步加在方法上,非常影响性能,因为单例方法往往会用得非常平凡,同步会带来很大的性能损耗。

饿汉式单例类在自己被加载时就将自己实例化。即便加载器是静态的,在饿汉式单例类被加载时仍会将自己实例化。单从资源利用效率角度来讲,这个比懒汉式单例类稍差些。
从速度和反应时间角度来讲,则比懒汉式单例类稍好些。然而,懒汉式单例类在实例化时,必须处理好在多个线程同时首次引用此类时的访问限制问题,特别是当单例类作为资源控
制器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费时间。这意味着出现多线程同时首次引用此类的机率变得较大。   



                  

评分

参与人数 2技术分 +4 收起 理由
wangfayin + 3 很给力!
刘蕴学 + 1

查看全部评分

回复 使用道具 举报
刘笑 中级黑马 2012-6-27 18:24:02
8#
两者主要区别是建立单例对象的时间不同。懒汉式是,只有用到这个用例的时候,再将他实例化,不会浪费,所以效率要高一些。
饿汉式则是程序只要开始,就将他实例化,到用到他的时候就省去了再实例的时间,所以速度和反应快。这是这俩的区别
不过差距不会那么明显。如果是做大项目,在效率上体现的就明显了

回复 使用道具 举报
whocases 黑马帝 2012-6-27 21:04:45
9#
二者只在创建对象的时候有区别,饿汉式是Single s=new Single();类加载时直接创建对象分配空间;
懒汉式是
Single s=null;
if(s==null)
s=new Single();
类加载时穿件对象但是不分配堆空间,指向为null,在对象被调用的时候再new,分配堆空间。

饿汉式一步完成,不会出现不安全因素;
而懒汉式分两步,可能多个线程在执行String s = null;后sleep();然后醒后创建多个对象,就违反了单例模式的规则,不安全。

开发中用饿汉式不用懒汉式也是出于安全考虑,看似懒汉式能更有效的利用堆栈空间,但是它不安全,若
用加锁来实现它的安全性又降低了效率,所以综合考虑还是用饿汉式。效率高,写代码方便,稍微占用一
些堆栈空间也是可以的。

这样说明白吗?

评分

参与人数 1技术分 +1 收起 理由
刘蕴学 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 Jackey 于 2012-6-28 11:54 编辑

这样是不是也是单例啊?
  1. <blockquote>public enum SingletonByEnum {
复制代码
回复 使用道具 举报
Jackey 发表于 2012-6-28 11:52
这样是不是也是单例啊?
  1. public enum SingletonByEnum {
  2.         INSTANCE
  3.         {
  4.                 public void someMethod()
  5.                 {
  6.                         // . . .
  7.                 }
  8.         };

  9.         protected abstract void someMethod();
  10. }
复制代码
回复 使用道具 举报
单例模式其实就是构造方法是私有的,通过getInstance()来取得实例。

package cn.ineeke.util;
/**
* 单利模式——懒汉式
* @author Neeke www.ineeke.com
*   
*/
public class DB {
    private static DB db = null;
     
    public static DB getInstance(){
        if(db == null){
            db = new DB();
        }
        return db;
    }
}
package cn.ineeke.util;
/**
* 单利模式——饿汉式
* @author Neeke www.ineeke.com
*   
*/
public class DB {
    private static DB db = new DB();
     
    public static DB getInstance(){
        return db;
    }
}
这种静态初始化的方法是自己被加载时就自己实例化,被形象的称之为饿汉式单例类。而原先的单例模式处理方式要在第一次被引用的时候才会被实例化,就被称为懒汉式单例类。
由于在多线程访问时懒汉式可能会出现创建出多个实例,而若对其使用synchronized的话,则又会降低程序性能。所以推荐使用饿汉式。
懒汉式是,只有用到这个用例的时候,再将他实例化,不会浪费,所以效率要高一些。
饿汉式则是程序只要开始,就将他实例化,到用到他的时候就省去了再实例的时间,所以速度和反应快。这是这俩的区别不过差距不会那么明显。
但是大项目,在效率上体现的就有点明显了。

点评

警告第三次,哪怕你在下边写了点不一样的,我也能看出来  发表于 2012-6-28 16:31
回复 使用道具 举报

玩单例模式其实就是为了用那唯一对象,获取对象 是单例里面肯定要做的事情,你先做后做都是要做的,所以你是都要创建对象 的,懒汉虽然是延时加载,但还是要加载,在这点上区别不是太大。但开发一般用饿汉式,因为饿汉式安全简单,在懒汉式中,如果 一个人来调用那个静态方法,没什么问题,但如果多个人同时 调用 的话,就容易出问题了。咱拿上面的例子说明吧
class Single
{
private static Single s=null;
private Single(){}
public static Single getInstance()
{
if(s==null)
s=new Single();
return s;
}
}
例如有一个a来调用方法,进来判断一下,s==空,它就进来了,如果正好这时cpu切换到别的程序上了,那a就先停那儿了,如果等一下b也来调用,因为if语句下面还没执行,s仍为空,好,b也进来了,然后cpu就没切,让b把下面执行了,new了一个对象,完了后又切到a了,因为a在之前已经判断过了,也该执行new对象那一步了,它就也new了一个对象,这样的话堆内就不是一个对象 了,就不符合单例模式的对象唯一性了,当然这个问题在多线程时可以用同步代码块解决,但总的说虽然懒汉式用的技术多,但没有饿汉式好用安全,所以一般都用饿汉式

点评

还有一点是效率问题,毕竟懒汉式运行时需要做额外的判断,效率差取决于你的调用次数  发表于 2012-6-28 17:50

评分

参与人数 1技术分 +1 收起 理由
刘蕴学 + 1

查看全部评分

回复 使用道具 举报
饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
懒汉式如果在创建实例对象时不加上synchronized则会导致线程安全问题
所以一般用饿汉式。

评分

参与人数 1技术分 +3 收起 理由
wangfayin + 3 总结得不错

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马