单例模式

单例模式的定义:
Ensure a class has only one instance,and provide a gloabl point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例)。

实现方法:把构造函数设置为private私有访问权限。然后只允许在本类中调用构造函数。进而达到“单例”。

优点:
1、由于单例模式在内存中只能生成一个实例,减少了内存开支,特别是一个对象需要频繁创建、销毁时,而且创建或销毁又无法优化的时候,单例模式的优势就特别明显。
2、由于单例模式只生成一个实例,所以减少了系统的性能开销,当对一个对象产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动是直接产生一个单例对象,然后永久驻留内存的方式来解决(在JAVA EE中采用单例模式时需要注意JVM垃圾回收机制)。
3、单例模式可以避免对资源的多重占用,例如一个写文件的动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时操作。
4、单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。

缺点:
1、单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本么有第二种途径可以实现。单例模式为什么不能增加接口呢?因为接口对单例模式是没有任何意义的,它要求“自行实例化”,并且提供单一实例、接口或抽象类是个不可能的杯实例化的。在特殊情况下,单例模式可以实现接口、被继承等,需要根据具体环境判断。
2、单例模式对测试是不利的,在并发开发环境中,如果单例模式没有完成,是不能进行测试的,没有接口也不能使用mock的方式虚拟一个对象。
3、单例模式与单一职责原则有冲突,一个类应该只实现一个逻辑,而不关心他是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。

单例模式的通用代码:
(也称为饿汉模式)

public class Singleton{

private static final Singleton singleton = new Singleton();
private Singleton (){
}
public static void main(args String[]){
return singleton;
}
public static void doSomething(){
}
}

单例模式的线程不安全性:
在高并发的情况下,请注意单例模式的线程同步问题。
线程不安全的例子:

public class Singleton {

private static Singleton singleton = null;

private Singleton(){

}
public static Singleton getSingleton(){

    if(singleton == null){
        singleton = new Singleton();
    }
    return singleton;
 }

}

该单例模式在低并发的情况下尚不会出现问题,但在高并发的情况下可能在内存中出现多个实例。为什么会出现这种情况?如果一个线程A执行到singleton = new Singleton();这一步,但是尚未获得对象,而线程B获得的判断条件也是为真。于是继续运行下去,线程A和线程A都获得了一个对象,在内存中就会出现两个对象。

因此,我们可以在采取线程同步。修改如下:

public class Singleton{
    private static Singleton singleton = null;
    public static synchronized synchronized getInstance(){
         if(singleton==null){
             singleton = new Singleton();
         }
        return singleton;
    }
} 

以上代码我们称为懒汉模式

饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的
推荐使用第一种
从实现方式来讲他们最大的区别就是懒汉式是延时加载,
他是在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,

饿汉式无需关注多线程问题、写法简单明了、能用则用。但是它是加载类时创建实例、所以如果是一个工厂模式、缓存了很多实例、那么就得考虑效率问题,因为这个类一加载则把所有实例不管用不用一块创建。

懒汉式的优点是延时加载、缺点是应该用同步(想改进的话现在还是不可能,比如double-check)、其实也可以不用同步、看你的需求了,多创建一两个无引用的废对象其实也没什么大不了。

单例模式的拓展:重点内容
一个类可以产生多个对象,这很容易实现,直接new就可以了,一个类只产生一个对象,我们可以采取单例模式。但是,如果我们需要两,三个对象,该怎么办了?

实现如下:

package Test;

import java.util.ArrayList;
import java.util.Random;

public class SingletonExpand {

    //最大生产对象数量
    private static int maxNum = 3;
    //用于存储对象的名字
    private static ArrayList<String> nameLists = new ArrayList<String>();
    //用于存储对象
    private static ArrayList<SingletonExpand> singletonlist = new ArrayList<SingletonExpand>();
    //当前对象序列号
    private static int countNum = 0;

    //产生所有的对象
    static{
        for(int i =0; i < maxNum ;i++){
            singletonlist.add(new SingletonExpand("对象" + i));
        }
    }
    //传入对象名,用来辅助对象的创建
    private SingletonExpand(String name){
        nameLists.add(name);

    }

    public static SingletonExpand getSingleton(){

        Random random = new Random();
        countNum = random.nextInt(maxNum);

        return singletonlist.get(countNum);
     }
    public void info(){
        System.out.println(nameLists.get(countNum));
    } 
}

client端代码:


public class client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        for(int i=0 ; i< 5;i++){
            SingletonExpand s = SingletonExpand.getSingleton();
            System.out.println("第"+(i+1)+"次访问的对象是");
            s.info();
        }
    }

}

终端输出为:
第1次访问的对象是
对象2
第2次访问的对象是
对象1
第3次访问的对象是
对象0
第4次访问的对象是
对象2
第5次访问的对象是
对象0

通过以上代码我们便实现了一个类中有好几个(两三个)对象。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值