定义
保证一个类只有一个实例,并提供一个访问它的全局访问点,并且自行实例化向整个系统提供。
使用场景
当一个类的实例可以有且只可以一个的时候就需要用到了。为什么只需要有一个呢?一方面是为了减少内存,另一方面(最重要的一方面)就是当实例存在多个会引起程序逻辑错误的时候。
单例的形式
- 懒汉式
public class Singleton{
//构造私有
private Singleton(){
}
private static Singleton instance = null;
//线程不安全,加同步锁
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
- 饿汉式
public class Singleton{
private Singleton(){
}
private static Singleton instance = new Singleton();
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance(){
return instance;
}
}
- 双重锁形式
public class Singleton{
//用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新的值。
private static volatile Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance=new Singleton();
}
}
}
return instance;
}
}
三种形式的比较
懒汉式:
在使用的时候创建对象,所以类加载快,运行慢,且线程不安全,故加同步锁。饿汉式:
在类加载的时候创建对象,所以类加载慢,运行快,线程安全。- 双重形式:
这个模式将同步内容下放到了if内部,提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了。这种模式中双重判断加同步的方式,比第一个例子中的效率大大提升,因为如果单层if判断,在服务器允许的情况下,假设有十个线程,耗费的时间为10*(同步判断时间+if判断时间),而如果双重if判断,10个线程可以同时if判断,理论消耗的时间只有一个if判断的时间。所以如果面对高并发的情况,而且采用的是懒汉模式,最好的选择就是双重判断加同步的方式。
PS:虽然单例模式是Java设计模式中最简单的一种,但是里面设计到的问题也是不能小觑的。比如线程安全问题和程序运行快慢等都应该是在平时开发当中注意的问题,对程序做一定的优化。