第一种:
饿汉式
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,因此既可以实现延迟加载,又可以保证线程安全,不影响系统性能