单例设计模式

它是解决某类问题的一套有效的方案(模版)。

一、单例代码书写步骤:

1、私有本类所有的构造方法;

2、创建本类的对象;

3、对外提供一个静态的方法来获取对象。

二、单例常用的两种书写格式:

1、饿汉式:

 1 class Single{
 2    //  私有所有构造方法
 3    private Single() {}
 4    //  在类中创建自己的对象
 5    private static Single instance = new Single();
 6    //  对外提供get方法,获取类中唯一的对象
 7    public static Single getInstance() {
 8         return instance;
 9    }
10 }

2、懒汉式:(常面)

 1 class Single{
 2     // 私有构造方法
 3     private Single(){}
 4     // 只定义变量,不创建对象
 5     private static Single instance = null;
 6     // 对外提供方法,获取本类对象
 7     public static Single getInstance() {
 8        // 不要直接返回,先判断instance中有没有对象
 9        if( instance == null ) {
10           // 判断成立,说明还没有唯一的对象,则创建对象
11           instance = new Single();
12         }
13           // 有则直接返回该对象
14         return instance;
15      }
16  }

三、常面问题:

1、单例解决的问题是什么?

保证当前的对象在程序中只有一个(对象唯一)。

2、单例模式方法上为什么要加静态?

添加静态的目的是保证外界可以通过类名调用该方法,从而拿到本类的唯一的那个对象。

因为这个类以外的地方没有办法创建类的对象,如果 getInstance 方法不是静态的,导致类以外的别的程序根本就无法获取到这个类的对象了,只有将 getInstance 方法静态了,外界才能通过唯一的这个方法来得到这个类的唯一的那个对象。

3、懒汉式在多线程操作的时候有没有安全问题?

有,在 getInstance 方法中的判断和赋值两行代码上操作共享的 instance 变量,这样在操作的过程中CPU会随机切换,可能出现安全问题。

解决方案:在判断和赋值代码上添加同步代码块。

4、添加同步时效率会降低,能不能优化?

可以。如下所示:

 1 class Single{
 2     private Single() {}
 3     private static Single instance = null; 
 4     /* a.可以定义一个对象作为同步的锁对象—-> synchronized(lock)
 5      *   private static Object lock = new Object();
 6      * b.因为是静态同步的方法,所以还可以使用格式:synchronized(Single.class)
 7      *
 8      * 1、此处添加静态的目的是保证外界可以通过类名调用方法名,从而拿到本类的唯一的那个对象   
 9      * 2、同步(synchronized)不能添加在此处方法上,会影响后续线程获取唯一对象的效率
10      */
11     public static Single getInstance()  {
12         /* 3、外面的判断目的是为了后续其他线程在获取对象时提供效率
13          *  当后续其他线程再调用getInstance方法时,由于instance变量中已经有对象了,
14          *  则判断不成立,线程就不用再进入到同步中,更不会判断同步的锁了,从而效率提高
15          */
16         if(instance == null) {
17             // 4、此处判断和赋值有安全问题,所以添加同步,保证多个线程只有一个线程能够创建对象
18             synchronized ( Single.class ) {
19                 if(instance == null) {
20                     instance = new Single();
21                 }
22             }
23         }
24         return instance;
25     }
26 }
27 //书写线程的任务类
28 class Demo implements Runnable{
29     public void run() {
30         System.out.println(Single.getInstance());
31     }
32 }
33 //书写一个测试类
34 public class SingleTest {
35     public static void main(String[] args) {
36         
37         //new一个实例对象
38         Demo t = new Demo();
39         
40         //创建线程并启动
41         new Thread(t).start();;
42         new Thread(t).start();;
43     }
44 }
45

5、能不能将 synchronized 添加到 run 方法上,为什么?

按照语法规则,是可以在run方法上书写同步的

但是在实际开发中是不可能在run方法上添加同步的。同步方法在线程执行的时候,每个线程要进入这个方法都需要获取同步锁,如果获取不到锁,线程就无法去执行这方法。而run方法是线程要执行的任务方法,如果线程都进不去run方法,相当于线程根本就没有拿到自己的任务。

 

有待继续完善…

版权声明:本文为zyouyi原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/zyouyi/p/11309964.html