单例模式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默认就是单例模式

线程池,数据库连接池,日志对象这些也用到了单例模式
---------------------

posted @ 2019-07-21 03:28  水至清明  阅读(178)  评论(0编辑  收藏  举报