例模式是在开发中用的最多的一种设计模式,那为什么会有单例设计模式呢?
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。从其名字中我们就可以看出所谓单例,就是单个实例也就是说它可以解决的问题是:可以保证一个类在内存中的对象的唯一性,在一些常用的工具类、线程池、缓存,数据库,账户登录系统、配置文件等程序中可能只允许我们创建一个对象,一方面如果创建多个对象可能引起程序的错误,另一方面创建多个对象也造成资源的浪费。在这种基础之上单例设计模式就产生了因为使用单例能够保证整个应用中有且只有一个实例.
二、单例模式的设计思想
单例模式的作用是为了保证程序中有且只有一个实例!
因此,设计思想也是围绕这个来展开:
1.私有化构造方法
因为要保证对象是唯一的,就不应该允许其他地方new对象了,因为每次new对象,都会开辟一个新的空间
2.通过自身的类创建对象
竟然不允许其他地方new对象了,那只能在本类中new对象
3.提供公共的方法,获取对象
在本类中new对象,其他地方要调用怎么办,只能在本类中提供方法,返回对象,让其他地方调用
三、单例模式的使用
1.饿汉式
package com.liangdianshui;
/**
* 单例模式Singleton 饿汉式
*
* 作用:保证整个应用程序中有且只有一个实例
*
* 饿汉式:在类加载的时候就完成了对象的实例化,从而避免了线程的同步问题,可是就是因为是
* 类加载,所以没有用到的时候也加载了,会造成内存的浪费,可是这个浪费是可以忽略的
*
* @author 两点水
*
*/
public class Singleton {
// 1.构造方法私有化,不允许外部创建实例
private Singleton() {
}
// 2.创建类的唯一实例
private static Singleton instance= new Singleton();
// 3.提供获取实例的公共方法
public static Singleton getInstance() {
return instance;
}
}
测试类:
package com.liangdianshui;
public class TestSingleton {
public static void main(String[] args) {
// 获取两个饿汉式的单例模式
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
// 判断是否是同一个实例
if (singleton1 == singleton2) {
System.out.println("相同的实例");
} else {
System.out.println("不是相同的实例");
}
}
}
package com.liangdianshui;
/**
* 单例模式Singleton 懒汉式
*
* 作用:保证整个应用程序中有且只有一个实例
*
* @author 两点水
*
*/
public class Singleton2 {
// 1.构造方法私有化,不允许外部创建实例
private Singleton2() {
}
// 2.创建类的唯一实例
private static Singleton2 instance = null;
// 3.提供获取实例的公共方法
public static Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
测试类:
package com.liangdianshui;
public class TestSingleton {
public static void main(String[] args) {
// 获取两个饿汉式的单例模式
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
// 判断是否是同一个实例
if (singleton1 == singleton2) {
System.out.println("相同的实例");
} else {
System.out.println("不是相同的实例");
}
// 获取两个懒汉式的单例模式
Singleton2 singleton3 = Singleton2.getInstance();
Singleton2 singleton4 = Singleton2.getInstance();
// 判断是否是同一个实例
if (singleton3 == singleton4) {
System.out.println("相同的实例");
} else {
System.out.println("不是相同的实例");
}
}
}
这种懒汉式相对饿汉式来说,加载类的时候速度相对来说比较快,但是运行时获取的对象速度比较慢,还有一个问题就是:饿汉式是不存在线程安全的问题,懒汉式存在线程安全的问题。为什么存在线程安全的问题呢?有多个线程去调用getInstance方法来获取Singleton的实例,那么就有可能发生这样一种情况当第一个线程在执行if(instance==null)这个语句时,此时instance是为null的进入语句。在还没有执行instance=new Singleton()时(此时instance是为null的)第二个线程也进入if(instance==null)这个语句,因为之前进入这个语句的线程中还没有执行instance=new Singleton(),所以它会执行instance=new Singleton()来实例化Singleton对象,因为第二个线程也进入了if语句所以它也会实例化Singleton对象。这样就导致了实例化了两个Singleton对象
因此我们改进上面的懒汉式:
package com.liangdianshui;
/**
* 单例模式Singleton 懒汉式
*
* 作用:保证整个应用程序中有且只有一个实例
*
* @author 两点水
*
*/
public class Singleton2 {
// 1.构造方法私有化,不允许外部创建实例
private Singleton2() {
}
// 2.创建类的唯一实例
private static Singleton2 instance = null;
// 3.提供获取实例的公共方法
public static Singleton2 getInstance() {
if (instance == null) {
synchronized (Singleton2.class) { // 增加线程锁
if (instance == null) {
instance = new Singleton2();
}
}
}
return instance;
}
}