003设计模式 -- 单例模式

第一种:

  饿汉式

 1 public class EagerLoadBalancer {
 2   private final static EagerLoadBalancer INSTANCE = new EagerLoadBalancer();
 3 
 4   private EagerLoadBalancer() {
 5   }
 6 
 7   public static EagerLoadBalancer getInstance() {
 8     return INSTANCE;
 9   }
10 
11   public static void main(String[] args) {
12     EagerLoadBalancer eagerLoadBalancer1 = EagerLoadBalancer.getInstance();
13     EagerLoadBalancer eagerLoadBalancer2 = EagerLoadBalancer.getInstance();
14     System.out.println("hashCode:"+eagerLoadBalancer1.hashCode());
15     System.out.println("hashCode:"+eagerLoadBalancer2.hashCode());
16   }
17 }

  分析

    利用class Load机制, 在加载时进行实例化, 同时静态方法只在编译期间执行一次初始化, 所以也就只有一个对象, 使用的时候已经被初始化完毕, 可以直接调用

    优点: 相比懒汉式, 编译期就已经初始化, 使用的时候速度最快

    缺点: 不使用也会被初始化出来, 消耗内存

第二种:
  懒汉式1
 1 public class LazyLoadBalancer1 {
 2   private static LazyLoadBalancer1 loadBalancer;
 3   private LazyLoadBalancer1() {
 4   }
 5 
 6   public static LazyLoadBalancer1 getInstance() {
 7     // 第一步:假设T1,T2两个线程同时进来且满足 loadBalancer == null
 8     if (loadBalancer == null) {
 9       // 第二步:那么 loadBalancer 即会被实例化2次
10       loadBalancer = new LazyLoadBalancer1();
11     }
12     return loadBalancer;
13   }
14 
15   public static void main(String[] args) {
16     LazyLoadBalancer1 balancer1 = LazyLoadBalancer1.getInstance();
17     LazyLoadBalancer1 balancer2 = LazyLoadBalancer1.getInstance();
18     System.out.println("hashCode:"+balancer1.hashCode());
19     System.out.println("hashCode:"+balancer2.hashCode());
20   }
21 }

  分析

    在单线程环境一切正常, balancer1和balancer2两个对象的hashCode一模一样. 由此可以判断出堆栈中只有一份内容, 不过该代码块中存在线程安全隐患. 因为缺乏竞争条件, 多线程环境资源竞争的时候就显得不太乐观了

对上面代码进行改造

 1 public class LazyLoadBalancer2 {
 2   private static LazyLoadBalancer2 loadBalancer;
 3   private LazyLoadBalancer2() {
 4   }
 5 
 6   public synchronized static LazyLoadBalancer2 getInstance() {
 7     // 第一步:假设T1,T2两个线程同时进来且满足 loadBalancer == null
 8     if (loadBalancer == null) {
 9       // 第二步:那么 loadBalancer 即会被实例化2次
10       loadBalancer = new LazyLoadBalancer2();
11     }
12     return loadBalancer;
13   }
14 
15   public static void main(String[] args) {
16     LazyLoadBalancer2 balancer1 = LazyLoadBalancer2.getInstance();
17     LazyLoadBalancer2 balancer2 = LazyLoadBalancer2.getInstance();
18     System.out.println("hashCode:"+balancer1.hashCode());
19     System.out.println("hashCode:"+balancer2.hashCode());
20   }
21 }

  分析

    毫无疑问,知道synchronized关键字的都知道, 同步方法在锁没释放之前,其它线程都在排队候着呢, 想不安全都不行啊,但在安全的同时,性能方面就显得短板了, 只初始化一次, 但是每次上来都要加个锁, 降低性能

  懒汉式2

 1 public class LazyLoadBalancer4 {
 2   private static LazyLoadBalancer4 loadBalancer;
 3 
 4   private LazyLoadBalancer4() {
 5   }
 6 
 7   private static class LoadBalancerHolder {
 8     private final static LazyLoadBalancer4 INSTANCE = new LazyLoadBalancer4();
 9   }
10 
11 
12   public static LazyLoadBalancer4 getInstance() {
13     return LoadBalancerHolder.INSTANCE;
14   }
15 
16   public static void main(String[] args) {
17     LazyLoadBalancer4 balancer1 = LazyLoadBalancer4.getInstance();
18     LazyLoadBalancer4 balancer2 = LazyLoadBalancer4.getInstance();
19     System.out.println("hashCode:"+balancer1.hashCode());
20     System.out.println("hashCode:"+balancer2.hashCode());
21   }
22 }

  分析

    我们在LazyLoadBalancer里增加一个静态(static)内部类, 在该内部类中创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用. 由于静态单例对象没有作为LazyLoadBalancer的成员变量直接实例化, 类加载时并不会实例化LoadBalancerHolder,因此既可以实现延迟加载,又可以保证线程安全,不影响系统性能

原文地址:https://www.cnblogs.com/yanwu0527/p/8573719.html