zoukankan      html  css  js  c++  java
  • 说说设计模式 单例模式

      一)单例模式的目的

      单例模式的目的是仅创建一个类的实例。

      二)思考如何构建单例

      在这里我们将用于构建该单例的类命名为MyProject,因为创建该实例的行为只能发生在MyProject的内部。而即便MyProject是包级私有(缺省修饰符:default)的,同一包下其它类仍可以访问到MyProject,因此为了避免同包其它类对MyProject构造器的访问,需要将构造器的访问权限定义为private但这里会导致一个问题,若想使用这个私有的构造器必须先有MyProject实例,但是MyProject实例却必须通过这个构造器产生,因此这里会陷入一个死循环。

      不过我们可以通过另外一种方式来实例化MyProject,见如下代码:

     1 public class MyProject {
     2     
     3     private static MyProject myProject;
     4 
     5     private MyProject()
     6     {
     7         
     8     }
     9     
    10     public static MyProject getInstance()
    11     {
    12         if(myProject == null)
    13         {
    14             myProject = new MyProject();
    15         }
    16         
    17         return myProject;
    18     }
    19     
    20 }

      三)经典单例模式的局限及其优化方案

      以上代码是常见的经典单例模式代码,但是在多线程场景下却隐藏着问题,可能会得到两个MyProject实例,这是因为两个线程之间的执行会互相切换(由CPU负责调度),可能线程一执行一半时切换到线程二再去执行,当线程二执行一半时可能又会切回线程一去执行,虽然二者最终都会执行完毕,但对于结果的正确性却不能做保证。

      因此在上述getInstance()方法定义时,需要加入synchronized关键字,但是该关键字的加入却会带来性能上的影响,因为只有在第一次创建MyProject时才会真的需要同步,一旦单个实例被创建成功,其它线程对该实例就不会造成什么影响,导致synchronized关键字就没有了存在的意义。那么有什么方法可以解决上述问题呢?

      以下是经过修改后的代码:

     1 public class MyProject {
     2     
     3     private volatile static MyProject myProject;
     4 
     5     private MyProject()
     6     {
     7         
     8     }
     9     
    10     public static MyProject getInstance()
    11     {
    12         if(myProject == null)
    13         {
    14             synchronized (MyProject.class)
    15             {
    16                 if(myProject == null)
    17                 {
    18                     myProject = new MyProject();
    19                 }
    20             }
    21         }
    22         
    23         return myProject;
    24     }
    25     
    26 }

      在myProject变量定义时加入了关键字volatile,该关键字的作用是当其它线程访问该变量时,会获取该变量的最新值,即保证所有线程访问到的这个变量值是一致的。在加入了这个关键字后,后续的线程再去调用这个方法时,执行第12行的if判断发现实例已经存在则直接执行23行的return返回实例,这样就不会触发synchronized同步块导致性能影响了。

  • 相关阅读:
    作业四 四则运算
    作业三
    作业二(3)
    作业二(2)
    作业二(1)
    作业一
    作业九
    每周更新学习进度表--第十一周
    每周更新学习进度表--第十周
    每周更新学习进度表--第九周
  • 原文地址:https://www.cnblogs.com/seker/p/5487778.html
Copyright © 2011-2022 走看看