初学设计模式【7】单例模式——sington

  有一些对象其实我们只需要一个,比如:线程池、缓存、充当显卡等设备的驱动程序的对象。这类对象只能有一个实例,否则会出现很多问题,资源消耗过多、数据不一致等。

定义

  确保一个类只有一个实例,并提供一个全局的访问点。

类图

  

说明:1.一个private static的Singleton实例变量instance.

   2.一个public static 的getInstance方法,返回instance。

   3.一个私有构造方法

经典实现

public class Singleton {
    private static Singleton instance = null;

    private Singleton() {
    }

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

}

 分析:为了保证类只有一个实例,Singleton类的构造方法需为private的这样外界不能通过new直接实例化对象,而只能通过Singleton提供的全局访问点getinstance方法获得,这样就保证了类对象的惟一性。

问题:这样写看上去很完美,实事上是这样吗?可,现实是残酷的,呵呵。

假设,我们有两个线程A,B同时访问上面的代码。假设A线程执行完if(instance == null)后时间片用完,然后B线程来访问上面的代码,假设B线程执行完了instance = new Singleton();即现在Singleton已经有了一个实例化对象。然后B时间片用完A线程回来接着执行,A线程要执行instance = new Singleton();这样就会带来一个问题,Singleton被实例化了两次。显然,这不是我们想要的,应该怎么解决呢?

解决方案:

  我们知道上面的问题是由线程同步问题造成的,那么我们可以直接将getinstance方法加上线程同步锁既可,如下:

1 public static synchronized Singleton getInstance() {
2         if (instance == null) {
3             instance = new Singleton();
4         }
5         return instance;
6     }

 新的问题:这样的确是没同步问题了,但线程同步会造成性能的降低,并且对于我们这种情况,我们实际上只需要在第一次进行同步(instance为null时),以后都不需要进行同步了,可我们上面的代码每次执行都会进行同步,显然这是不合理的,那应该怎么解决呢?

方案A:提前初始化instance。

  如果我们的程序总是创建并使用单例实例,或者在创建和运行方面的负担不太繁重,你可以提前实例化instance,如下所示:

 1 public class Singleton {
 2     private static Singleton instance = new Singleton();
 3 
 4     private Singleton() {
 5     }
 6 
 7     public static synchronized Singleton getInstance() {
 8         return instance;
 9     }
10 
11 }

 利用此方法,我们可以在JVM加载这个类时就创建此惟一的对象。JVM保证在任何线程访问instance之前,一定先创建此实例。

 方案B:双重检查锁   

 1 public static Singleton getInstance()
 2 {
 3   if (instance == null)
 4   {
 5     synchronized(Singleton.class) {  
 6       if (instance == null)          
 7         instance = new Singleton();  
 8     }
 9   }
10   return instance;
11 }

 通过此方法既可保证只在instance为null的时候才进行同步,保证了性能。

原文地址:https://www.cnblogs.com/byghui/p/3057870.html