所有类都有构造方法,如果不编写则系统默认生成空的构造方法,若有显示定义的构造方法,默认的构造方法就会失效。
将构造方法写成是private的,那么外部程序就不能用new来实例化它了。
单例模式: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法
单例模式因为类封装它的唯一实例,这样他可以严格的控制客户怎样访问它以及何时访问它。简单地说就是对唯一实例的受控访问。
多线程时的单例模式
1.懒汉模式
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new singleton();
return singleton;
}
}
这种写法只能在单线程下使用,如果是多线程,可能发生一个线程通过并进入了if (singleton == null)判断语句块,但还未来得及创建新的实例时,另一个线程也通过了这个判断语句,两个线程最终都进行了创建,导致多个实例的产生,所以在多线程环境下必须摒弃此方式
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
这种写法通过给getInstance()
方法添加了synchronized
关键字,迫使每个线程在进入这个方法前,要先等候别的线程离开该方法,即不会有两个线程可以同时进入该方法执行new Singleton()
,从而保证了单例的有效,但它的致命缺陷是效率太低了,每个线程每次执行getInstance()
方法获取类的实例时,都会进行同步,而事实上实例创建完成后,同步就变为不必要的开销了,这样做在高并发下必然会拖垮性能。
2.双重检查锁定(Double Check Lock) 简称:DCL
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
synchronized(Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
此方法的Double-Check
体现在进行了两次if (singleton == null)
的检查,这样即同步代码块保证了线程安全,同时实例化的代码也只会执行一次,实例化后同步操作不会再被执行,从而效率提升很多。
Android中鼎鼎大名的Universal Image Loader和EventBus都是采用了这种方式
public class SpHistoryStorage {
private Context context;
private static SpHistoryStorage instance;
private SpHistoryStorage(Context context) {
this.context = context.getApplicationContext();
}
public static synchronized SpHistoryStorage getInstance(Context context) {
if (instance == null) {
synchronized (SpHistoryStorage.class) {
if (instance == null) {
instance = new SpHistoryStorage(context);
}
}
}
return instance;
}
}
这是我在看别人的代码的时候,人家这样写的。
后面的部分我都是看的这篇文章潜谈单例模式这篇文章写的很详细