zoukankan      html  css  js  c++  java
  • 单例模式(Singleton)(单一实例)

    单例模式基本要点:

    用于确保一个类只有一个实例,并且这个实例易于被访问。

    让类自身负责保存他的唯一实例。这个类可以保证没有其他实例创建,并且他可以提供一个访问实例的方法,来实现单例模式。

    (1)把构造方法声明为 private ,确保只能由自己创建,避免外部创建实例或被子类继承从而创建额外实例。

    (2)定义一个私有静态的该类的实例作为该类的数据域,确保一个类只有一个实例。

    (3)定义一个静态工厂方法,外部类不能实例化一个该类的对象,所有只能用static的方法,提供给其它类调用返回此单例类的唯一实例。

    回收站单例类:

     1 import java.security.KeyStore.PrivateKeyEntry;
     2 
     3 public class RecycleBin {
     4 private static RecycleBin recycleBin = null;
     5 /*
     6  * 
     7  *private 构造方法 保证其他类不能通过   new  创建实例
     8  */
     9 private  RecycleBin() {
    10     System.out.println("回收站被创建!");
    11 }
    12 
    13 public static RecycleBin getrecyclebin() {
    14     
    15     if (recycleBin==null) {
    16         recycleBin = new RecycleBin();
    17     }else {
    18         System.out.println("系统只能有一个回收站,不能重复!");
    19     }
    20     
    21     return recycleBin;
    22 }
    23 
    24 void clearbin(){
    25     System.out.println("回收站被清空!");
    26 }
    27 
    28 }

    客户测试类:

     1 public class SingletonPattern {
     2 
     3     public static void main(String[] args) {
     4         RecycleBin x = RecycleBin.getrecyclebin();
     5         x.clearbin();
     6         RecycleBin y = RecycleBin.getrecyclebin();
     7         x.clearbin();
     8         if(x==y){
     9             System.out.println("x和y是相同的实例");
    10         }else {
    11             System.out.println("x和y不是相同的实例");
    12         }
    13     }
    14 
    15 }

     但是涉及到多线程仍然无法保证单例。

    线程类:

    1 public class Mythread extends Thread {
    2     @Override
    3     public void run() {
    4 RecycleBin x = null;
    5 x=RecycleBin.getrecyclebin();
    6 System.out.println(x+":"+x.hashCode());
    7 
    8     }
    9 }

    客户测试类:

    public class SingletonPattern {
    
        public static void main(String[] args) {
    for(int i = 0;i<10;i++){
        Mythread mythread = new Mythread();
        mythread.start();
    }
        }
    
    }

    测试结果:

    com.Singleton.windowRecycleBin.RecycleBin@3c648a9d:1013222045
    com.Singleton.windowRecycleBin.RecycleBin@10533d95:273890709
    com.Singleton.windowRecycleBin.RecycleBin@3b9cec95:1000139925
    com.Singleton.windowRecycleBin.RecycleBin@28a4ac8:42617544
    com.Singleton.windowRecycleBin.RecycleBin@4bb40e1:79380705
    com.Singleton.windowRecycleBin.RecycleBin@63e13bff:1675705343
    com.Singleton.windowRecycleBin.RecycleBin@51ea99e2:1374329314
    com.Singleton.windowRecycleBin.RecycleBin@dbfdd93:230677907

    解决方法 1:使用synchronized关键字

                 synchronized 的英文意思是“被同步,已同步了”,该该关键字的作用就是为并发线程提供一种同步机制,用于保证在同一时刻最多只有一个线程来执行某段事先定义好要求同步访问的代码。因此,我们可以将一个方法标记为synchronized,迫使线程在执行这个方法前,要等待其他线程离开这个方法,这样就不会有两个线程同时操作该方法了。

                   于是修改单例类,在getrecyclebin()方法之前加上synchronized关键字,其它代码不变。

                    加上synchronized关键字之后,线程得到的是一个实例,但是这里又引出一个问题·:效率。每次调用getrecyclebin()的时候都要进行同步,会造成负担。

    解决方法 2:双重检查加锁(不适用于1.4及以前版本的java)

                       利用双重检查加锁,首先检查是否已实现了实例  ,如果还没创建才进行同步,这样只会有第一次同步,效率自然会提高。

        单例类:

     1 import java.security.KeyStore.PrivateKeyEntry;
     2  
     3  public class RecycleBin {
     4  private static RecycleBin recycleBin = null;
     5  /*
     6   * 
     7   *private 构造方法 保证其他类不能通过   new  创建实例
     8   */
     9  private  RecycleBin() {
    10      System.out.println("回收站被创建!");
    11  }
    12  
    13  public static RecycleBin getrecyclebin() {
    14      if (recycleBin==null) {
    15          synchronized (RecycleBin.class) {
    16              if (recycleBin==null) {
    17              recycleBin = new RecycleBin();
    18          }else {
    19              System.out.println("系统只能有一个回收站,不能重复!");
    20          }
    21          
    22     }
    23     }
    24      return recycleBin;
    25      
    26     }
    27 
    28  void clearbin(){
    29      System.out.println("回收站被清空!");
    30      }
    31  
    32  }
    synchronized只加在能判断或函数外,如果加在   recycleBin = new RecycleBin();  上无法起到作用。
    因为在第一次访问时,线程的 recycleBin 都为空。必须保证后续线程无法进入判断,否则后续线程仍会创建。

    解决方法 3:饿汉式单例

    懒汉式:

                    懒汉式单例指的是当程序第一次访问单例模式实例时才进行创建。

                   体现对象延迟加载的思想,效率高。尽可能的节约资源,但设计不当会造成线程不安全,代码相对于饿汉式复杂。第一次加载类对象时反应不快。必须处理好多个线程同时访问的问题,需通过双重锁等机制进行控制,可能会导致系统性能受影响。

    饿汉式:

                    饿汉式单例是当程序启动时或单例被加载时,单例类实例就已经创建,所有一开始就new了实例。

                     对象预先加载,线程是安全的,反应速度快。但是资源利用不高,系统加载时间可能会比较长。

          滥用单例模式的负面影响:如为了节省资源而将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出,如果实例化对象长时间不被利用,系统会认为是垃圾而将其回收,这将导致对象状态的丢失。            

  • 相关阅读:
    在 XD 和 Axure 中使用 iconfont
    chartjs 曲线图 纪要
    js ajax 等的的一些纪要
    程序员的方向
    sqlserver 常用的练习50例子
    (function(){})()原理
    layer弹出层详解
    sqlserver 表值函数 保存使用
    关于批量下载线程池与信号机制的使用
    tp5.1 phpstudy composer 配置等
  • 原文地址:https://www.cnblogs.com/the-wang/p/7270073.html
Copyright © 2011-2022 走看看