单例模式

单例模式

单利模式有很多种实现方式,每一种方式都有自己合适的场合。常用的单利有:懒汉式、饿汉式、线程安全式、双重检查式和登记式。

实现单利最重要的一点是构造方法是private的,这使得实例不能被外界所创建。

 

懒汉式

 

这是最简单的一种单利模式,但是带来的问题是线程不安全。这里所谓的不安全是指在创建第一个实例时是线程不安全的。可以看到,当我们初次使用时才会创建实例,所以叫懒汉式。

 1 public class SimpleSingleton {
 2 
 3     private static SimpleSingleton simpleSingleton;
 4 
 5     //必须为private,这是实例独一无二的保证
 6     private SimpleSingleton(){
 7 
 8     }
 9 
10     public static SimpleSingleton getInstance(){
11         //如果不存在则实例一个
12         if(simpleSingleton==null){
13             //创建第一个实例时是线程不安全的
14             simpleSingleton = new SimpleSingleton();
15         }
16         return simpleSingleton;
17     }
18 }

线程安全式

为了解决线程安全的问题,我们只需要在获得实例的方法上同步即可,但是这就会造成程序性能下降。

 1 public class SafeSingleton {
 2 
 3     private static SafeSingleton safeSingleton;
 4 
 5     // 必须为private,这是实例独一无二的保证
 6     private SafeSingleton() {
 7 
 8     }
 9 
10     //保证线程安全
11     public static synchronized SafeSingleton getInstance() {
12         // 如果不存在则实例一个
13         if (safeSingleton == null) {
14             safeSingleton = new SafeSingleton();
15         }
16         return safeSingleton;
17     }
18 }

饿汉式

可以看到,在JVM加载这个类时,就会创建实例。JVM能保证在任何线程访问到eagerSingleton实例之前将其创建完成。

 1 public class EagerSingleton {
 2 
 3     //JVM加载这个类时就创建
 4     private static EagerSingleton eagerSingleton = new EagerSingleton();
 5 
 6     private EagerSingleton(){};
 7 
 8     public static EagerSingleton  getInstance(){
 9         return eagerSingleton;
10     }
11 }

双重检查

线程安全式中,同步了整个getInstance方法才保证了线程安全,会浪费很多性能。于是我们可以使用双重检查式,它将只在初次创建实例的时候实现同步。(了解锁优化的同学可以理解为减少锁的颗粒度)

 1 public class DoubleCheckSingleton {
 2 
 3     private volatile static DoubleCheckSingleton doubleCheckSingleton;
 4 
 5     private DoubleCheckSingleton() {
 6     };
 7 
 8     public static DoubleCheckSingleton getInstance() {
 9         //这里没有加synchronized
10         if (doubleCheckSingleton == null) {
11             //很多线程都能到达这里
12             synchronized (DoubleCheckSingleton.class) {
13                 //有可能已经有线程更早一步创建了单利
14                 if (doubleCheckSingleton == null)
15                     doubleCheckSingleton = new DoubleCheckSingleton();
16             }
17         }
18         return doubleCheckSingleton;
19     }
20 }

登记式

虽然和饿汉式一样使用了静态域,但是此种方式的实例加载是Lazy的。

 1 public class StaticSingleton {
 2 
 3     // 利用了 classloder 机制来保证初始化 instance 时只有一个线程
 4     private static class SingletonHolder {
 5         private static final StaticSingleton INSTANCE = new StaticSingleton();
 6     }
 7 
 8     private StaticSingleton() {
 9     }
10 
11     public static final StaticSingleton getInstance() {
12         return SingletonHolder.INSTANCE;
13     }
14 }

 

posted on 2018-08-14 20:20  东子z  阅读(134)  评论(0编辑  收藏  举报

导航