单例设计模式(Java),
单例设计模式(Java),
单例模式
即表示内存中只有一个该类的实例,可以节约内存、提高性能。
常见的做法有两种:懒汉式和饿汉式。
饿汉式
这里的“饿汉”是说,不管调用端代码是否最终需要一个本例的实例,都先在内存中创建好。
代码
public class Singleton {
private static Singleton singleton = new Singleton();
public static Singleton getNewInstance() {
return singleton;
}
}
分析
饿汉式逻辑简单,线程安全,但是存在性能改良的空间,因为如果静态方法从来没有被调用过,在内存中new出一个对象完全没有必要。
懒汉式
与饿汉式相对应,懒汉式的“懒”体现在只有调用了静态方法才创建实例,如果从来没有调用过,就不创建实例。
代码
public class Singleton {
private static Singleton singleton;
public static Singleton getNewInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
分析:这种做法保证内存中只有一个该类的实例,也做到了只有真正调用了才开辟内存创建对象,但是线程不安全。
如果有不止一个线程在调用此方法,A刚判断实例为空,进去new对象了,但是还没new完并赋值给singleton的时候,B也进来,此时singleton还是null,所以也进来new了一个对象,所以就会出现new了两个对象,出现了线程不安全的问题。
可以做如下改良:
public class Singleton {
private static Singleton singleton;
//给方法加同步
public static synchronized Singleton getNewInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
给方法加上同步之后就能保证线程安全了,但是每次调用方法的时候,都需要进行同步判断,性能太差。
然后就可做如下改良:
public class Singleton {
private static Singleton singleton;
public static Singleton getNewInstance() {
if (singleton == null) {
//语句块同步
synchronized (Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
这样应该没什么问题了,但是细细分析来看,线程还是不同步的。
比如:A线程判断为null后进来了,并进入同步块new对象,此时B线程进来了判断还是null,照样进入了if块,因为同步,所以只能在外边等着,当A线程走出同步块,B线程进入,也new了个对象,也导致了线程不安全的问题。基于以上分析,可以得到思路,在同步块里再判断一次ok了!
终极版本:
public class Singleton {
private static Singleton singleton;
public static Singleton getNewInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
//再次判断,即使另一个线程进来了,也不会做任何事情。
if(singleton==null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
分析:这样就可以保证即时另一个线程顺利进入了外层if块,但是当前一个线程走出同步块的时候,singleton已经非空了,第二个线程进入了同步块,也不会做任何事情就会退出,最终return的还是唯一的一个实例。这应该就是懒汉式的最终版本了。
最终比较
这两种设计方法都可以实现单例模式,饿汉式简单,如果对内存要求不是很严格可以采用,懒汉虽然更加复杂,但是更加高效,应该尽量使用此方法。
相关文章
- 暂无相关文章
用户点评