单例模式Singleton
单例模式
保证一个类只有一个实例,并且提供一个访问他的全局访问点 --《设计模式:可复用面向对象软件的基础》84页3.5节
在某些情况下我们需要一个类在任何情况下 只需要同一个实例并且提供一个访问该实例的方法
单例模式又分懒汉和饿汉模式
懒汉模式:在你需要他的时候才会去创建对象,也就是你在调用访问该实例的方法的时候才会去创建
/**
* 单例模式 :懒汉模式
*
* @author 爱出走的眼睛
*
*/
public class Singleton {
private static Singleton singleton;
private Singleton() {
System.out.println("创建对象");
}
public static Singleton GetInstance() {
if (singleton==null) {
singleton=new Singleton();
}
return singleton;
}
}
//测试代码
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
System.out.println(s1==s2);
//结果为 true
上述代码并非严格,因为没有考虑到多线程的环境下 下面我测试一下在多线程情况下出现的问题
public class Test {
public static void main(String[] args) {
Thread tA = new Thread() {
public void run() {
Singleton.GetInstance();
}
};
Thread tB = new Thread() {
public void run() {
Singleton.GetInstance();
}
};
tA.start();
tB.start();
}
}
打印结果为:
创建对象
创建对象
因为在多线程的情况下 线程A可能在创建对象之前cpu时间片用完了进入就绪状态,线程B分配到资源 这个时候由于线程A没有执行完创建对象语句,此时线程B判断依然对象为空,所以线程B也会去创建对象,这样两个线程都进入了if里面 导致单例模式失败!
严格的单例模式 懒汉
/**
* 单例模式 :严格的懒汉模式
*
* @author 爱出走的眼睛
*
*/
public class Singleton {
//使用volatile 关键字 禁止指令排序
private static volatile Singleton singleton;
private Singleton() {
}
public static Singleton GetInstance() {
//这里 锁代码块比锁方法更加高效
if (singleton==null) {
synchronized(Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
如果不懂volatile 和线程的话 需要自己补习一下同步锁和volatile 关键字
饿汉模式: 不管你调用不调用 它都会去创建这个对象
饿汉代码就简单很多
public class SingletonHungry {
//注意这里使用了final关键字
private static final SingletonHungry singleton=new SingletonHungry();
private SingletonHungry() {
}
public static SingletonHungry GetInstance(http://www.my516.com) {
return singleton;
}
}
应用场景
最简单的一个小例子 windows系统中的任务管理器 无论你打开多少次任务管理器 他只会有一个窗口
因为如果你打开两个任务管理器窗口 且内容一样 管理器需要去调用CPU去获取这些信息 这样设计的目的是为了减少资源浪费 所以设计成单例模式,第二点 如果你打开两个管理器发现内容不一样 这样更容易给用户带来误解。
spring中的bean默认就是单例模式
线程池,数据库连接池,日志对象这些也用到了单例模式
---------------------