zoukankan      html  css  js  c++  java
  • java多线程与单例模式(Singleton)不得不说的故事

    转发自:http://blog.csdn.net/ligang7560/article/details/50890282

    单例模式的多种实现方式

    我们都知道单例模式有几种常用的写法:
    - 饿汉模式
    - 懒汉模式
    - 双重校验锁
    - 静态内部类
    - 静态代码块
    我们来看一下这几种模式在多线程的场景中,能否保持单例

    1.饿汉模式

    public class HungrySingleton {
    
        //立即加载模式
        private static HungrySingleton hungrySingleton = new HungrySingleton();
    
        private HungrySingleton(){}
    
        public static HungrySingleton getInstance(){
            return hungrySingleton;
        }
    
    }
    
    

    接下来我们写一个线程类,再写一个测试类,来看下饿汉模式在多线程下的表现如何:这里写图片描述

    运行测试类结果如下:

    	546862187
    	546862187
    	546862187
    

    这说明饿汉模式是线程安全,在多线程的情况下,也能够保持单例.

    2.懒汉模式

    public class LazySingleton {
    
        private static LazySingleton lazySingleton;
    
        private LazySingleton() {}
    
        public static LazySingleton getInstance(){
            if(lazySingleton!=null){
            }else{
                lazySingleton =  new LazySingleton();
            }
            return lazySingleton;
        }
    
    
    }
    

    同样的我们来写一个线程类,写一个测试类;
    这里写图片描述
    运行结果:

    	2030251396
    	546862187
    	2030251396
    

    我们看到对象返回的哈希值不一致了,这就说明他们已经不是同一个对象实例了,也就是说这种写法是线程不安全的,那么我们对它进行如下的改造:

    public class LazySingleton {
    
        private static LazySingleton lazySingleton;
    
        private LazySingleton() {}
    
        //整个方法加同步,效率低
        synchronized public static LazySingleton getInstance(){
            if(lazySingleton!=null){
            }else{
                lazySingleton =  new LazySingleton();
            }
            return lazySingleton;
        }
    }
    

    我们给整个getInstance方法添加了个synchronized关键字,才保证多线程的情况下也能保持单例,我们再运行一下测试类:

    1638084561
    1638084561
    1638084561
    

    这时我们看见已经没有问题了,就是说写法是正确的,但是这种写法导致所以并发的线程获取实例时都是排队进行的,那么就会导致性能低下,接下来我们尝试另外一种写法,就是我们的第三种写法:双重校验锁.

    3. 双重校验锁

    public class LazySingleton {
    
        private static LazySingleton lazySingleton;
    
        private LazySingleton() {}
    
         public static LazySingleton getInstance(){
            if(lazySingleton!=null){
            }else{
                synchronized (LazySingleton.class){
                    if(lazySingleton==null){
                        lazySingleton =  new LazySingleton();
                    }
                }
    
            }
            return lazySingleton;
        }
    }
    

    我们将排队进行的范围进行缩小,同时采用校验两次为空的方法,来保证单例模式的正确性,接下来我们来看一下测试结果:

    2030251396
    2030251396
    2030251396
    

    OK,没有问题.

    4.静态内部类

    public class StaticInnerClassSingleton {
    	//通过写一个静态的内部类来创建实例
        private static class SingletonHandle{
            private static StaticInnerClassSingleton singleton = new StaticInnerClassSingleton();
        }
    
        private StaticInnerClassSingleton(){}
    
        public static StaticInnerClassSingleton getInstance(){
            return SingletonHandle.singleton;
        }
    
    }
    

    测试类和上面的都差不多,我就不贴图片了,直接看测试结果:

    1523917841
    1523917841
    1523917841
    

    没有问题,这种方式也是线程安全的,接下来我们看最后一种方式

    5.静态代码块

    public class StaticSingleton {
    
        private static StaticSingleton staticSingleton=null;
    
        private StaticSingleton(){};
    	
        static {
    	//通过静态代码块的执行,来获取实例
            staticSingleton = new StaticSingleton();
        }
    
        public static StaticSingleton getInstance(){
            return staticSingleton;
        }
    }
    

    不废话了,直接看测试结果:

    2030251396
    2030251396
    2030251396
    

    没有问题,那么以上我们就介绍了5中关于多线程中单例模式的写法,其中呢就懒汉模式的一般写法容易造成错误,其他的写法都是线程安全的,文章中的代码我已经上传到github了,有需要的同学可以下载下来自己试试.
    https://github.com/JokerLigang/Singleton.git

  • 相关阅读:
    [习题]输入自己的生日(年/月/日)#2 -- 日历(Calendar)控件的时光跳跃,一次跳回五年、十年前?--TodaysDate属性、VisibleDate属性
    Interesting effects
    kendoGrid methods方法
    kendoListBox 选择控件
    kendo format
    kendoGrid Event事件
    kendoGrid的一些基础配置
    kendoGrid edit功能
    kendoDatePicker日期选择控件
    Json与DataSet转化
  • 原文地址:https://www.cnblogs.com/j2eeDevelper/p/5286158.html
Copyright © 2011-2022 走看看