美文网首页
java 单例模式

java 单例模式

作者: 不懂zhuang懂的年岁 | 来源:发表于2016-09-10 23:18 被阅读27次

    单例模式有以下特点:
    1.单例类只能有一个实例(该类只能有一个实例)
    2.单例类必须自己创建实例
    3.单例类必须给所有其他对象提供这一实例
    计算机系统中,如线程池、缓存、日志对象、驱动程序等被设置成单例。在多线程环境下,可能有一些同步问题。
    如下代码所示:

    public class TestStream {
         private String name;
         public String getName() {
             return name;
         }
         public void setName(String name) {
             this.name = name;
         } 
         //该类只能有一个实例
         private TestStream(){}    //私有无参构造方法
         //该类必须自行创建
         //有2种方式
         /*private static final TestStream ts=new TestStream();*/
         private static TestStream ts1=null;//懒汉单例模式
         //这个类必须自动向整个系统提供这个实例对象
         public static TestStream getTest(){//这里用的是懒汉单例模式
             if(ts1==null){
                 ts1=new TestStream();
             }
             return ts1;
         }
         public void getInfo(){
             System.out.println("output message "+name);
         }
     }
    public class TestMain {
         public static void main(String [] args){
             TestStream s=TestStream.getTest();
             s.setName("张孝祥");
             System.out.println(s.getName());
             TestStream s1=TestStream.getTest();
             s1.setName("张孝祥");
             System.out.println(s1.getName());
             s.getInfo();
             s1.getInfo();
             if(s==s1){
                 System.out.println("创建的是同一个实例");
             }else if(s!=s1){
                 System.out.println("创建的不是同一个实例");
             }else{
                 System.out.println("application error");
             }
         }
     }
    

    运行结果: 
    张孝祥  
    张孝祥  
    output message 张孝祥  
    output message 张孝祥  
    创建的是同一个实例
    懒汉单例模式:默认不自动实例化,等用的时候根据当前情况实例化

    public class Singleton{
      private static Singleton instance = null;
      private Singleton(){}
      public static Singleton getInstance(){
        if(instance == null)  
            return new Singleton();
         else
            return instance;
    }
    }
    

    饿汉单例模式:在类第一次加载的时候强制实例化

    public class Singleton{
      private static Singleton instance = new Singleton();
      private Singleton(){}
      public static Singleton getInstance(){
            return instance;
    }
    }
    

    单例模式的线程同步问题:
    两个线程,一个发现变量是null,准备创建变量,第二个也发现变量是null,创建变量,就会造成在一个JVM中有多个单例类型的实例。
    解决线程安全的方案:
    1.使用synchronized方法对getInstance()方法进行同步

    public class Singleton{
      private static Singleton instance = null;
      private Singleton(){}
      public synchronized  static Singleton getInstance(){
        if(instance == null)  //mark1
            return new Singleton();//mark2
         else
            return instance;
    }
    }
    

    2.双重锁
    但是用synchoronized会导致性能下降,我们想要的只是mark1和mark2的同步,所以可以不把synchronized加在方法上,而是加在代码块里

    public class Singleton{
      private static volatile Singleton instance;
      
      private static Singleton(){}
      
      public static Singleton getSingleton(){
          if(instance == null){//mark1
            synchronized(Singleton.class){
                if(instance == null)//mark2
      return new Singleton();
                 return instance;
    }
    return instance;
    }    
    
    }
    }
    

    这里用了两个判断,原因:如果两个线程同时到达mark1处,synchronized可以保证线程不同时进行,但两个线程会一个个执行,所以还要在synchronized代码块中再次判断,防止创建两个。
    这个也叫作双重锁。
    3.使用静态内部类
    这种方法拥有单例、延迟创建(参见饿汉模式)和线程同步的优点,利用静态内部类来实现

    public class Singleton{
        private static Singleton(){}
        
        private static class Lazyholder{
         private static final Singleton instance = new Singleton();
    }
    
      public static Singleton getSingleton(){
      return Lazyholder.instance;
    }
    }
    

    当类被加载时,由于没有static代码,所以不会有操作。当第一次执行getSingleton()方法时,内部静态类会被加载,创建外部单例类实例,在内部类加载过程中,静态类只会被加载一次,static属性和static初始化块的执行是串行的,这就保证了不会有两个线程同时new Singleton()

    相关文章

      网友评论

          本文标题:java 单例模式

          本文链接:https://www.haomeiwen.com/subject/fspasttx.html