不考虑线程安全问题的时候单例模式的代码:
1 class Bank { 2 //把该类的构造器声明为私有 3 private Bank() { 4 5 } 6 //设置私有化静态类变量 7 private static Bank instance = null; 8 9 //设置获取该实例的静态方法 10 public static Bank getInstance() { 11 if (instance == null) { 12 instance = new Bank(); 13 } 14 return instance; 15 } 16 }
分析:
单例模式通俗来说就是要求我们在创建某一个对象的时候只能创建一个这个类的对象。在多线程的情况下,可能会有多个线程在各自的run()方法中调用public static Bank getInstance()方法创建类的对象实例,如果有一个线程再调用方法且未执行完毕的时候发生阻塞,那么另外一个线程也会执行这个方法,这个时候就会有两个线程同时创建对象实例,这就违背了单例模式的初中,显然这样是线程不安全的,因此我们需要针对这个问题解决线程安全问题。
解决办法:
在单例模式中我们可以把instance这个对象实例看成是一个共享数据,我们需要使用同步代码快或者是同步方法来解决共享数据的线程安全问题。
1 package com.baozi.java; 2 3 public class BankTest { 4 //....... 5 } 6 /** 7 * 这是一个单例模式的类: 8 * 线程安全问题的分析:在多线程的情况下这个单例模式是非线程安全的,多线程的时候会有多个线程通过 9 * public static Bank getInstance()方法来获取对象实例,如果某一个线程在进行判断对象实例是否已经被初始化的时候 10 *对象实例为空,紧接着会进入if()内进行创建对象实例的过程,如果在此时发生阻塞,那么下一个线程抢占到cpu执行权, 11 * 这时该线程也会进行判断且对象实例也为空同样要进去执行创建对象实例的操作,这样两个实例都要进行创建对象 12 * 实例,此时是会出现线程安全问题的。 13 *线程安全问题的解决:我们可以使用synchronized代码块或者synchronized方法来解决线程安全问题。 14 * 1、如果使用synchronized方法来解决线程安全问题: 15 * public static synchronized Bank getInstance() { 16 * if (instance == null) { 17 * instance = new Bank(); 18 * } 19 * return instance; 20 * } 21 * 2、如果使用synchronized代码块来解决线程安全问题: 22 * public static Bank getInstance() { 23 * synchronized (Bank.class) { 24 * if (instance == null) { 25 * instance = new Bank(); 26 * } 27 * return instance; 28 * } 29 * } 30 * 或者是:这种方法效率要比上面全部放在synchronized代码块中的效率要高 31 * public static Bank getInstance() { 32 * if(instance == null){ 33 * synchronized (Bank.class) { 34 * if (instance == null) { 35 * instance = new Bank(); 36 * } 37 * } 38 * } 39 * return instance; 40 * } 41 */ 42 class Bank { 43 //把该类的构造器声明为私有 44 private Bank() { 45 46 } 47 //设置私有化静态类变量 48 private static Bank instance = null; 49 50 //设置获取该实例的静态方法 51 public static Bank getInstance() { 52 if(instance == null){ 53 synchronized (Bank.class) { 54 if (instance == null) { 55 instance = new Bank(); 56 } 57 } 58 } 59 return instance; 60 } 61 }