您的位置:首页 > 其它

单例模式

2016-03-18 17:29 381 查看
单例模式的定义:

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

通过以上代码我们便实现了一个类中有好几个(两三个)对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息