设计模式之单例模式——Singleton

               

                    设计模式之单例模式——Singleton

设计意图:

 保证类仅有一个实例,并且可以供应用程序全局使用。为了保证这一点,就需要这个类自己创建自己的对象,并且对外有公开的调用方法而且,别的类不能实例化它,所以构造方法要设置为私有的。

单例模式的要点   

一是某个类只能有一个实例;

二是它必须自行创建这个实例;

三是它必须自行向整个系统提供这个实例。

例如:

有一个"单例对象",而"客户甲""客户乙" "客户丙"是单例对象的三个客户对象。可以看到,所有的客户对象共享一个单例对象。而且从单例对象到自身的连接线可以看出,单例对象持有对自己的引用。一些资源管理器常常设计成单例模式。在计算机系统中,需要管理的资源包括软件外部资源,譬如每台计算机可以有若干个打印机,但只能有一个Printer Spooler, 以避免两个打印作业同时输出到打印机中。每台计算机可以有若干传真卡,但是只应该有一个软件负责管理传真卡,以避免出现两份传真作业同时传到传真卡中的情况。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。

实现的方法:

单例模式有很多种,下面就来介绍一下单例模式的几种使用方法吧:
【饿汉模式】饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。

public   class   Singleton{
    private static final Singleton singleton = new Singleton();
    /**
     * 私有构造函数
     */
    private   Singleton(){
        
    }
    /**
     * 获得实例
     * @return
     */
    public static Singleton getInstance(){
        return singleton;
    }
    public static void say(){
        System.out.println("单例模式创建啦!");
        
    }
}
public class main {
    public static void main(String[] args) {
        main m=new main();
        Singleton.getInstance().say();
    }

}

这样做的好处是编写简单,但是无法做到延迟创建对象。但是我们很多时候都希望对象可以尽可能地延迟加载,从而减小负载,所以就需要下面的懒汉法:

 【懒汉法】

 这种方法可以实现延时加载,但是有一个致命弱点:线程不安全。如果有两条线程同时调用getSingleton()方法,就有很大可能导致重复创建对象。

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

解决线程不安全的三种方法:

1、在getInstance方法上加同步

 

public static synchronized Singleton getInstance() {  
         if (single == null) {    
             single = new Singleton();  
         }    
        return single;  
} 
 

2、双重检查锁定

synchronized (Singleton.class),相当于在Singleton对象上加了锁,任何一个线程如果的到了这把锁就可以先运行,直到到他执行完其他线程才有可能得到这把锁,再进入执行。
public static Singleton getInstance() {  
        if (singleton == null) {    
            synchronized (Singleton.class) {    
               if (singleton == null) {    
                  singleton = new Singleton();   
               }    
            }    
        }    
        return singleton;   
    }  
 

3、静态内部类

 

public class Singleton {    
    private static class LazyHolder {    
       private static final Singleton INSTANCE = new Singleton();    
    }    
    private Singleton (){}    
    public static final Singleton getInstance() {    
       return LazyHolder.INSTANCE;    
    }    
}    

思考:java中单例模式和静态类(一个类,所有方法为静态方法)的区别

由于单例模式和静态类都具有良好的访问性,它们之间有许多相似之处,例如,两者可以直接使用而无须创建对象,都可提交唯一实例,在一个非常高的高度上看起来它们都为是用于同样的任务。

1.那么在java中什么时候该使用单例模式,什么时候该使用静态类呢?

       如果你的单例不需要维护任何状态,仅仅提供全局访问的方法,这种情况考虑使用静态类,静态方法比单例更快,因为静态的绑定是在编译期就进行的。但是要记住,不建议在静态类中维护状态信息,特别是在并发环境中,若无适当的同步措施而修改多线程并发时,会导致坏的竞态条件。
      如果你需要将一些工具方法集中在一起时,你可以选择使用静态方法,但是别的东西,要求单例访问资源时,应该使用单例模式。
 
2.Java中单例(变现类)与静态类(表现方法)的区别
1)静态类比单例具有更好的性能,因为静态方法在编译期绑定。
2)再次,它们的区别是override的能力,因Java中的静态方法是不可以覆盖的,这就导致其木有太多的灵活性,另一面,你可通过继承的方式覆盖单例类中定义的方法。
3)静态类很难模拟,因此难于单例测试,单例更容易模拟,因为也比静态类易于编写单元测试,不论神马单例期望神马,你都可以传递模拟对象,例如构造方法或方法参数。
4)如果你的需求中需要维护状态信息,则单例比静态类更适合,因为后者在维护状态信息方面是非常可怕的,并导致狡滑的bug。
5)如果是一个非常重的对象,单例可以懒加载,但是静态类没有这样的优势,并且非常热切的加载。
6)许多依赖注入的框架对单例都有良好的管理,例如Spring,使用它们非常容易。
 
 
3.Java中,选择单例而不是静态类的优点
单例与静态主要的优点是前者比后者更具有面向对象的能力,使用单例,可以通过继承和多态扩展基类,实现接口和更有能力提供不同的实现,如果我们讨论java.lang.Runtime,在Java中它是单例,调用getRuntime()方法,会基于不同的JVM返回不同的实现,但也保证了每个JVM中实有一个实例,如果java.lang.Runtime是一个静态类,不太可能因不同的JVM返回不同的实现。
 
这就是Java中单例与静态类的区别,当你需要一个全能力的对象时,选择单例,如果仅仅是将一些静态方法预售,使用静态类。
 
原文地址:https://www.cnblogs.com/java-7/p/6053540.html