说说设计模式 单例模式

  一)单例模式的目的

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

  二)思考如何构建单例

  在这里我们将用于构建该单例的类命名为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同步块导致性能影响了。

原文地址:https://www.cnblogs.com/seker/p/5487778.html