×

单例模式的优缺点 单例模式的好处 单例模式

单例模式的好处和缺点为什么要用单例模式详细才给分?单例模式代码怎么写

admin admin 发表于2022-06-10 21:19:22 浏览116 评论0

抢沙发发表评论

单例模式的好处和缺点为什么要用单例模式详细才给分


1 单例模式 只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等
2 单例的缺点 就是不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
用单例模式,就是在适用其优点的状态下使用。

单例模式代码怎么写


 单例模式(Singleton) ,属于最常见的设计模式之一,大部分系统都会用到,目的是为了维护系统中唯一的一个实例。
  可分为eager模式,示例代码如下:
  Java代码
  1.class EagerSingleton{
  2. private static final EagerSingleton m_instance = new EagerSingleton();
  3. private EagerSingleton(){}
  4. public static EagerSingleton getInstance(){
  5. return m_instance;
  6. }
  7.}
  class EagerSingleton{
  private static final EagerSingleton m_instance = new EagerSingleton();
  private EagerSingleton(){}
  public static EagerSingleton getInstance(){
  return m_instance;
  }
  }
  和 lazy模式,示例代码如下:
  Java代码
  1.class LazySingleton{
  2. private static LazySingleton m_instance = null;
  3. private LazySingleton(){}
  4. public synchronized static getInstance(){
  5. if(m_instance == null){
  6. m_instance = new LazySingleton();
  7. }
  8. return m_instance;
  9. }
  10.}
  class LazySingleton{
  private static LazySingleton m_instance = null;
  private LazySingleton(){}
  public synchronized static getInstance(){
  if(m_instance == null){
  m_instance = new LazySingleton();
  }
  return m_instance;
  }
  }
  java源码中,Runtime.getRuntime()就是单例的一个例子。
  单例模式的精神就是整个系统中维护一个实例,推广开来,如果在一个系统中需要维护多个示例,那么就产生了多例模式(multiton)。
  多例模式(Multiton) ,通过聚集对象了保留自身的多个示例,根据客户端的参数返回所需要的实例。
  示例代码如下:
  Java代码
  1.class Multiton{
  2. private final int INSTANCE_SIZE = 10;
  3. private static Map instances = new HashMap(INSTANCE_SIZE);
  4. private String name;
  5. private Multiton(){}
  6. private Multiton(String name){
  7. this.name = name;
  8. }
  9. public synchronized static getInstance(String name){
  10. if(instances.containsKey(name)){
  11. return instances.get(name);
  12. }
  13. else{
  14. ins = new Multiton(name);
  15. instances.put(name, ins);
  16. return ins;
  17. }
  18. }
  19.}
  class Multiton{
  private final int INSTANCE_SIZE = 10;
  private static Map instances = new HashMap(INSTANCE_SIZE);
  private String name;
  private Multiton(){}
  private Multiton(String name){
  this.name = name;
  }
  public synchronized static getInstance(String name){
  if(instances.containsKey(name)){
  return instances.get(name);
  }
  else{
  ins = new Multiton(name);
  instances.put(name, ins);
  return ins;
  }
  }
  }
  [nextpage]
  一个实用的例子就是KeyGenerator, 示例代码如下:
  Java代码
  1.class KeyGenerator{
  2. private final int POOL_SIZE = 20;
  3. private static Map instances = new HashMap(16);
  4. private KeyInfo keyinfo;
  5. private KeyGenerator(){}
  6. private KeyGenerator(String keyName){
  7. this.keyinfo = new KeyInfo(POOL_SIZE, keyName);
  8. }
  9. public synchronized static getInstance(String keyName){
  10. if(instances.containsKey(keyName)){
  11. return (KeyGenerator)instances.get(keyName);
  12. }
  13. else{
  14. keyGen = new KeyGenerator(keyName);
  15. instances.put(name, keyGen);
  16. return keyGen;
  17. }
  18. }
  19. public synzhronized int getNextKey(){
  20. return keyinfo.getNextKey();
  21. }
  22. }
  class KeyGenerator{
  private final int POOL_SIZE = 20;
  private static Map instances = new HashMap(16);
  private KeyInfo keyinfo;
  private KeyGenerator(){}
  private KeyGenerator(String keyName){
  this.keyinfo = new KeyInfo(POOL_SIZE, keyName);
  }
  public synchronized static getInstance(String keyName){
  if(instances.containsKey(keyName)){
  return (KeyGenerator)instances.get(keyName);
  }
  else{
  keyGen = new KeyGenerator(keyName);
  instances.put(name, keyGen);
  return keyGen;
  }
  }
  public synzhronized int getNextKey(){
  return keyinfo.getNextKey();
  }
  }

java中的单例模式的代码怎么写


我从我的博客里把我的文章粘贴过来吧,对于单例模式模式应该有比较清楚的解释:
单例模式在我们日常的项目中十分常见,当我们在项目中需要一个这样的一个对象,这个对象在内存中只能有一个实例,这时我们就需要用到单例。

一般说来,单例模式通常有以下几种:

1.饥汉式单例

public class Singleton {
private Singleton(){};
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}

这是最简单的单例,这种单例最常见,也很可靠!它有个唯一的缺点就是无法完成延迟加载——即当系统还没有用到此单例时,单例就会被加载到内存中。
在这里我们可以做个这样的测试:

将上述代码修改为:

public class Singleton {
private Singleton(){
System.out.println(“createSingleton“);
};
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
public static void testSingleton(){
System.out.println(“CreateString“);
}
}

而我们在另外一个测试类中对它进行测试(本例所有测试都通过Junit进行测试)

public class TestSingleton {
@Test
public void test(){
Singleton.testSingleton();
}
}

输出结果:

createSingleton
CreateString

我们可以注意到,在这个单例中,即使我们没有使用单例类,它还是被创建出来了,这当然是我们所不愿意看到的,所以也就有了以下一种单例。

2.懒汉式单例

public class Singleton1 {
private Singleton1(){
System.out.println(“createSingleton“);
}
private static Singleton1 instance = null;
public static synchronized Singleton1 getInstance(){
return instance==null?new Singleton1():instance;
}
public static void testSingleton(){
System.out.println(“CreateString“);
}
}

上面的单例获取实例时,是需要加上同步的,如果不加上同步,在多线程的环境中,当线程1完成新建单例操作,而在完成赋值操作之前,线程2就可能判
断instance为空,此时,线程2也将启动新建单例的操作,那么多个就出现了多个实例被新建,也就违反了我们使用单例模式的初衷了。

我们在这里也通过一个测试类,对它进行测试,最后面输出是

CreateString

可以看出,在未使用到单例类时,单例类并不会加载到内存中,只有我们需要使用到他的时候,才会进行实例化。

这种单例解决了单例的延迟加载,但是由于引入了同步的关键字,因此在多线程的环境下,所需的消耗的时间要远远大于第一种单例。我们可以通过一段测试代码来说明这个问题。

public class TestSingleton {
@Test
public void test(){
long beginTime1 = System.currentTimeMillis();
for(int i=0;i《100000;i++){
Singleton.getInstance();
}
System.out.println(“单例1花费时间:“+(System.currentTimeMillis()-beginTime1));
long beginTime2 = System.currentTimeMillis();
for(int i=0;i《100000;i++){
Singleton1.getInstance();
}
System.out.println(“单例2花费时间:“+(System.currentTimeMillis()-beginTime2));
}
}

最后输出的是:

单例1花费时间:0
单例2花费时间:10

可以看到,使用第一种单例耗时0ms,第二种单例耗时10ms,性能上存在明显的差异。为了使用延迟加载的功能,而导致单例的性能上存在明显差异,
是不是会得不偿失呢?是否可以找到一种更好的解决的办法呢?既可以解决延迟加载,又不至于性能损耗过多,所以,也就有了第三种单例:

3.内部类托管单例

public class Singleton2 {
private Singleton2(){}
private static class SingletonHolder{
private static Singleton2 instance=new Singleton2();
}
private static Singleton2 getInstance(){
return SingletonHolder.instance;
}
}

在这个单例中,我们通过静态内部类来托管单例,当这个单例被加载时,不会初始化单例类,只有当getInstance方法被调用的时候,才会去加载
SingletonHolder,从而才会去初始化instance。并且,单例的加载是在内部类的加载的时候完成的,所以天生对线程友好,而且也不需要
synchnoized关键字,可以说是兼具了以上的两个优点。

4.总结

一般来说,上述的单例已经基本可以保证在一个系统中只会存在一个实例了,但是,仍然可能会有其他的情况,导致系统生成多个单例,请看以下情况:

public class Singleton3 implements Serializable{
private Singleton3(){}
private static class SingletonHolder{
private static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
}

通过一段代码来测试:

@Test
public void test() throws Exception{
Singleton3 s1 = null;
Singleton3 s2 = Singleton3.getInstance();
//1.将实例串行话到文件
FileOutputStream fos = new FileOutputStream(“singleton.txt“);
ObjectOutputStream oos =new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
//2.从文件中读取出单例
FileInputStream fis = new FileInputStream(“singleton.txt“);
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (Singleton3) ois.readObject();
if(s1==s2){
System.out.println(“同一个实例“);
}else{
System.out.println(“不是同一个实例“);
}
}

输出:

不是同一个实例

可以看到当我们把单例反序列化后,生成了多个不同的单例类,此时,我们必须在原来的代码中加入readResolve()函数,来阻止它生成新的单例

public class Singleton3 implements Serializable{
private Singleton3(){}
private static class SingletonHolder{
private static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
//阻止生成新的实例
public Object readResolve(){
return SingletonHolder.instance;
}
}

再次测试时,就可以发现他们生成的是同一个实例了。
-单例模式的优缺点