单例设计模式
它是解决某类问题的一套有效的方案(模版)。
一、单例代码书写步骤:
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方法,相当于线程根本就没有拿到自己的任务。
有待继续完善…