设计模式之单例(singleton)设计模式代码详解
单例有两种:懒汉式和饿汉式
/** * 懒汉式的单例模式 * 这种单例模式如果采用到多线程调用该方法,有可能会产生多个实例,原因是: * 当线程一进入了①处,此时轮到线程二的时间片,线程二也来到①处,则两个线程各自会创建实例,这样就不满足单例模式的目标了 * 解决办法有三种: * 1.将懒汉式转换成饿汉式,当类加载的时候就完成对该实例的创建,这样多线程操作的时候只会获取该实例而不会创建该实例,自然也不会产生多个实例了 * 2.在getInstance方法前加入synchronized关键字 * 3.“双重检查加锁” * User: HYY * Date: 13-11-15 * Time: 下午12:28 * To change this template use File | Settings | File Templates. */ public class LazySingleton { private static LazySingleton mySingleton; private LazySingleton(){} public static LazySingleton getInstance() { if(mySingleton==null) { //① mySingleton = new LazySingleton(); } return mySingleton; } public void businessMethod() { System.out.println("业务方法"); } public static void main(String[] args) { LazySingleton singleton = LazySingleton.getInstance(); singleton.businessMethod(); LazySingleton singleton2 = LazySingleton.getInstance(); System.out.println("1==2:"+(singleton==singleton2)); } }
这种单例模式如果采用到多线程调用该方法,有可能会产生多个实例,原因是:
当线程一进入了①处,此时轮到线程二的时间片,线程二也来到①处,则两个线程各自会创建实例,这样就不满足单例模式的目标了
解决办法有三种:
* 1.将懒汉式转换成饿汉式,当类加载的时候就完成对该实例的创建,这样多线程操作的时候只会获取该实例而不会创建该实例,自然也不会产生多个实例了
* 2.在getInstance方法前加入synchronized关键字
* 3.“双重检查加锁”
/** * 饿汉式单例模式 * 这种单例模式能够解决多线程创建多个实例对象的问题 * 采用了这种方式再也不用担心多线程对该对象的多次实例 * 当类被加载的时候就已经初始化该实例,如果该类是一个庞大的实例,常驻一大块内存,则这样不是一个好设计。应当在需要的时候再去实例该对象(懒汉式) * User: HYY * Date: 13-11-15 * Time: 下午12:38 * To change this template use File | Settings | File Templates. */ public class HungrySingleton { private static HungrySingleton hungrySingleton = new HungrySingleton(); private HungrySingleton(){} public HungrySingleton getInstance() { return hungrySingleton; } }
/** * 在getInstance方法前面添加synchronized关键字解决多线程的问题。 * * 如果有很多线程要获取这个单例,则这种设计方式比较低效。为什么? * 要知道synchronized关键字有可能使程序的效率降低100倍。 * User: HYY * Date: 13-11-15 * Time: 下午12:34 * To change this template use File | Settings | File Templates. */ public class SyncSingleton { private static SyncSingleton syncSingleton; private SyncSingleton(){} public synchronized static SyncSingleton getInstance() { if(syncSingleton==null) { syncSingleton = new SyncSingleton(); } return syncSingleton; } }
/** * 我们其实只需要保证在创建的时候有只有一个线程负责该单例的创建即可。 * 因此我们采用“双重检查加锁”方式(即只加锁创建实例部分的代码) * * User: HYY * Date: 13-11-15 * Time: 下午12:56 * To change this template use File | Settings | File Templates. */ public class DoubleCheckSingleton { private volatile static DoubleCheckSingleton syncSingleton; private DoubleCheckSingleton(){} public static DoubleCheckSingleton getInstance() { if(syncSingleton==null) {//如果还没有进行实例化 //① synchronized (DoubleCheckSingleton.class) {//准备进入创建操作,在此之前先判断创建操作是否已经加锁 if(syncSingleton==null) {//再次判断是否已经加锁,如果没有这句判断,那么已经进入①处的线程还会进行实例化 syncSingleton = new DoubleCheckSingleton(); } } } return syncSingleton; } }
本文出自 无忧之路 - 博客园