@XQF
2016-12-21T10:56:47.000000Z
字数 2338
阅读 1119
java设计模式-----实验楼
就是被单例的对象只能有一个实例存在。单例模式的事项方式是:一个类只能返回对象的一个引用(永远是同一个)和一个获得该唯一实例的方法(必须是静态方法)通过单例模式,我们可以保证系统中只有一个实例,从而在某些特定的场合下达到节约或者控制系统资源的目的
单例模式有很多种的实现
最常见的就是饿汉模式,最简单。一上来就是新建一个实例。但是这种方法有一个明显的缺点就是不管有没有获得过实例的方法,每次都会新建一个实例
public class Wife {
// 一开始就新建一个实例,这是自引用?
private static final Wife wife = new Wife();
// 默认的构造方法
public Wife() {
// TODO Auto-generated constructor stub
}
// 获得实例的方法
public static Wife getWife() {
return wife;
}
}
最常见,最简单之二。就是开始的时候不创建实例,只有在需要使用的时候才创建实例,会先判断实例是否为空,如果为空才会新建一个实例来使用
public class Wife {
// 一开始没有新建一个实例
private static Wife wife;
// 默认的构造方法
public Wife() {
// TODO Auto-generated constructor stub
}
// 需要时才创建
public static Wife getWife() {
if (wife == null) {
wife = new Wife();
}
return wife;
}
}
懒汉模式确实很简单,但是要注意的是上面的懒汉模式存在一个严重的问题。就是如果有多个线程并行使用getWife()方法的时候,还是会创建多个实例,单例模式就失效了。
于是我们在懒汉模式的基础上,把它设为线程同步。synchronized的作用就是保证在同一时刻最多只有一个线程运行,这样就避免了多线程带来的麻烦
public class Wife {
// 一开始没有新建一个实例
private static Wife wife;
// 默认的构造方法
public Wife() {
// TODO Auto-generated constructor stub
}
// 添加了关键字
public static synchronized Wife getWife() {
if (wife == null) {
wife = new Wife();
}
return wife;
}
}
线程安全的懒汉模式解决了多线程的问题,但那时效率并不高,每次调用获取实例的getWife()方法时都要进行同步,但是多数情况下是不需要进行同步操作的(比如在wife实例并不为空可以直接使用的时候,就不需要加同步方法,直接返回实例),所以只需要在第一次新建实例对象的时候使用同步方法
public static Wife getWife() {
if (wife == null) {//第一次为空的时候
synchronized (Wife.class){//同步创建
if (wife==null) {
wife=new Wife();
}
}
}
return wife;
}
注意这里并没有结束,主要问题在于wife=new Wife()
因为在JVM执行这句代码的时候,要做好几件事情,而JVM为了优化代码,有可能造成做这几件事情的执行顺序是不固定的,从而造成错误。因此我们要阻止代码自行进行优,于是加上一个volatile
关键字
```java
//双重检验锁的最终式
public class Wife {
// 一开始没有新建一个实例
private volatile static Wife wife;
// 默认的构造方法
public Wife() {
// TODO Auto-generated constructor stub
}
// 需要时才创建
public static Wife getWife() {//第一次为空的时候
if (wife == null) {
synchronized (Wife.class){//同步创建
if (wife==null) {
wife=new Wife();
}
}
}
return wife;
}
}
java
#### 静态内部类
`volatile`关键字在老版本中JDK是无法正常工作的。这种静态内部类的方式,利用了JVM自身的机制来保证线程安全。因为`WifeHloder`是私有的,除了getWife()之外没有其他方式可以访问实例对象,而且只有在调用`getWife()`时才会真正创建实例对象
public class Wife {
private static class WifeHolder {
private static final Wife wife = new Wife();
}
private Wife() {
}
public static Wife getWife() {
return WifeHolder.wife;
}
}
java
#### 枚举
代码很是简单,可以通过`Wife.INSTANCE`来访问对象,这比`getWife()`简单得多,而且创建枚举默认就是线程安全的,还可以防止反序列化带来的问题
public enum Wife {
INSTANCE;
// 自定义的其他任何方法
public void whateverMethod() {
}
}
```
当你只需要一个实例对象的时候,就可以考虑使用单例模式。比如在资源共享的情况下,避免由于多个资源操作导致的性能或损耗等,就可以使用单例模式。Config类里面就是使用的单例模式?