java中的单例设计模式

一,单例模式----饿汉式
单例模式是设计模式中的一种,百科资料显示有23种设计模式,每种设计模式都是为了解决特定的
某个问题而设计的一套相对固定的编码流程!设计模式也区分为多种不同的类型,例如生产对象型、
桥接型、代理型等,单例模式属于生产对象型的设计模式。

    单例(单一实例,实例=对象)模式的目标:在同一时间,某个类的对象最多只可能存在1个,不会

存在2个或更多个对象!

    假设存在`UserService`类:

    public class UserService {}

则可以随意创建若干个对象:
UserService service1 = new UserService();
UserService service2 = new UserService();
UserService service3 = new UserService();

很显然,如果可以随意创建对象,是不符合单例模式的设计初衷的!之所以可以随意创建对象,是因为
该类没有显式的声明构造方法,会导致编译器为这个类自动添加默认构造方法(公有的、无参数的),
所以,以上类的代码等效于:
public class UserService {

    public UserService() {
            super();
     } 
    }

为了限制对象的创建过程,可以将类的构造方法私有化,一旦显式的定义了构造方法,则编译器不会再
自动添加构造方法:
public class UserService {

    // 将构造方法的权限改为private
    private UserService() {
            super(); // 这句代码可以省略,编译器也会自动添加
    }

    }

则在类的外部将不可以通过UserService service = new UserService();这样代码来创建对象了!

    为了保证还是可以创建对象,甚至被类的外部获取对象,可以在类中自行创建,并对外提供获取对象的

方法:
public class UserService {

     // 在类的内部依然可以通过构造方法来创建对象
     private UserService userService = new UserService();

    private UserService() {
     }

    // 对外提供获取对象的方法
    public UserService getInstance() {
    return userService;
    }
     }
    但是,以上代码是矛盾的,因为:如果要调用`getInstance()`方法,就必须先得到类的对象,但是,

得到类的对象的方式就是调用getInstance()方法!也就是说:没有对象就不能调用getInstance()
法,但是,不调用getInstance()方法就无法得到对象!

    为了解决这个矛盾,需要在`getInstance()`方法上添加`static`修饰符:
    public class UserService {

     private UserService userService = new UserService();

     private UserService() {
     }

    // 添加static修饰符
    public static UserService getInstance() {
            return userService;
    }

    }

则可以通过类名.方法名()来调用方法,也就是UserService.getInstance();即可获取对象!

注意:以上代码是错误的,因为“被static修饰的成员不可以直接访问非static成员”!也就是说:
getInstance()方法中是不可以访问(返回)userService对象的!

为了解决问题,还需要为userService属性也添加static修饰符:
public class UserService {

// 添加static修饰符
private static UserService userService = new UserService();

private UserService() {
}

public static UserService getInstance() {
    return userService;
}

}
至此,饿汉式单例模式就完成了(另外还有懒汉式的单例模式)!

注意:默认情况下,Spring框架管理的对象都具有“单例”的特点,但是,这些对象的类型并不是通过单
例模式来设计的,只是这些对象具有“单例”的特点而已!所以,不要把Spring框架和单例模式混为一谈,
它们之间没有任何关系!

注意:由于单例模式中,对象是添加了static关键字进行修饰的,所以,单例的对象都具有“常驻内存”
的特点!

二,单例模式—懒汉式

饿汉式的单例模式的特点是:当类被加载时就直接创建了单例的对象,即使接下来很长的时间里都没有调用
getInstance()方法(也可以是别的名字,指的就是获取对象的方法),这个单例的对象也是存在的,可
能形成一些资源浪费。

懒汉式的单例模式的特点是:不到逼不得已,不会创建对象!也就是说,当类被加载时,单例的对象是没有
被创建出来的,仅当第1次获取对象时,才会创建对象!

public class UserService {

private static UserService userService = null;

private UserService() {
}

public static UserService getInstance() {
    if (userService == null) {
        userService = new UserService();
    }
    return userService;
}

}

以上代码就是懒汉式的单例模式的原型!但是,以上代码是存在线程安全问题的,当对象还没有被创建出来时,
如果有多个线程几乎同时运行以上代码,就可能创建出多个对象!

为了解决线程安全问题,可以将以上代码片断添加互斥锁:
public class UserService {

private static UserService userService = null;

private UserService() {
}

public static UserService getInstance() {
    synchronized ("java") {
        if (userService == null) {
            userService = new UserService();
        }
    }
    return userService;
}

}
当添加了锁之后,线程安全问题就被解决了,但是,也会导致“每次获取对象之前都需要先锁定代码才可以
执行”,会导致多线程“同时”执行时效率低下,为了解决这个问题,还可以:

public class UserService {

private static UserService userService = null;

private UserService() {
}

public static UserService getInstance() {
    // 判断有没有必要锁住代码
    if (userService == null) {
        // 锁住代码
        synchronized ("java") {
            // 有没有必要创建对象
            if (userService == null) {
                userService = new UserService();
            }
        }
    }
    return userService;
}

}

至此,懒汉式的单例模式已经完成!

关于2种单例模式的对比:

  • 饿汉式:由于早早的创建了对象,所以,可以随时获取对象,则获取对象的效率非常高,但是,也可能
    因为创建出来后长时间没有调用对象,会导致对象无谓的占用内存,会形成浪费;
  • 懒汉式:由于获取对象之前不会创建对象,所以,不存在无谓占用内存的问题,但是,最简单的懒汉式
    单例模式是存在线程安全问题的,即使解决了线程安全问题,每次获取对象时都需要先经过一次判断,相
    比饿汉式的直接获取对象,效率是偏低的!另外,如果第一次获取对象时,正巧是服务器比较忙的时候,
    还加大了服务器的负担!

相比之下,饿汉式的优势更加明显,它仅仅只是在第一次获取对象之前会无谓的占用内存,以当今的服务
器的性能而言,一个简单的对象所占用的内存空间完全是可以忽略不计的,而懒汉式的缺点在于每一次获
取对象时都要先经过一次判断,是长期的消耗!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值