单例模式要点:
- 确保一个类只有一个对象实例
- 提供一个全局访问点
- 在java中实现单例模式需要私有的构造器、一个静态的方法和一个静态变量
- 确定在性能和资源的限制上,选择合适的方案来实现单例模式
- 若使用多个类加载器,可能会导致单例失效而产生多个实例。
构建单例模式:
- 将类的构造方法的访问权限设置为private,因此我们不能通过new操作符,在类的外部产生类的对象。
- 由于该类的实例是在类的内部产生,因此在类的外部不能得到类的对象,因此需要调用该类的某个静态方法,以返回类内部创建的对象。
- 由于静态方法只能访问类中的静态成元,因此该类对象的变量也需要定义为静态。
单例模式有如下构造方式:
1.饿汉式
所谓饿汉式是指在类装载的时候就完成了实例化,减小了创建时的开销。同时避免了多线程的问题,保证了线程安全。特点就是在静态初始化器中创建单例。(每次创建都必须立即拥有该对象)
//1.私有化构造器,使得在类的外部不能调用此构造器
private Singleton() {
}
//2. 在类的内部创建一个类的实例
private static Singleton INSTANCE = new Singleton();
//3. 私有化此对象,通过公共方法来调用,此公共方法,只能通过类来调用,因此类的实例也必须为static声明
public static Singleton getInstance(){
return INSTANCE;
}
2.懒汉式(线程不安全)
可能存在线程安全,在不同的线程中可能new多个对象
/**
* 懒汉式(存在线程安全问题)
*/
private Singleton() {
}
private static Singleton INSTANCE;
public static Singleton getInstance(){
if (INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
3.懒汉式(线程安全)
通过线程同步,解决了线程不安全的问题,但是效率太低,在每个线程中执行getInstance()都要进行同步。
/**
* 懒汉式(线程安全,同步方法)
*/
private Singleton(){
}
private static Singleton INSTANCE;
public static synchronized Singleton getInstance(){
if (INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
4.懒汉式(线程安全,同步代码块)
由于第三种模式效率低,因此改为同步代码块的方式,但是这种同步不能实现线程同步的作用,如果一个线程进入了if(INSTANCE == null)判断语句,但是没能往下执行,而另一个线程则通过了该判断语句,就会产生多个实例。
/**
* 懒汉式(线程安全,同步代码块)
*/
private Singleton(){
}
private static Singleton INSTANCE;
public static Singleton getInstance(){
if (INSTANCE == null){
synchronized (Singleton.class){
INSTANCE = new Singleton();
}
}
return INSTANCE;
}
5.双重检查(线程安全)
为了解决4中的问题,在启动了synchronized后,再判断对象是否为空,确保了类对象为单例。
/**
* 双重检查
*/
private Singleton() {
}
private static Singleton INSTANCE;
public static Singleton getInstance(){
if (INSTANCE == null){
synchronized (Singleton.class){
if (INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;