游戏人生看别样风景

首页 » Java笔记 » 正文

单例模式的两种实现方法及线程安全

2014年06月05日 | 分类:Java笔记 | 作者:hucker | 评论:0条评论 | 浏览:831

单例模式是23种设计模式中比较常用的模式之一,它的定义是一个类只有一个实例,并提供一个全局访问点就是在应用环境中一个类只能创建一个对象实例,这样处理是因为有些场景如:线程池、缓存、日志对象、打印机对象等只能有一个实例,若有多个,则会产生程序、资源等等问题。

单例模式的创建方法有两种:懒汉式和饿汉式

.延迟实例化方式(懒汉式)(非线程安全)

单例模式的实现方式很简单,即将构造器设为私有(private),不允许其他类通过new方式创建对象,并对外提供一个返回该类实例的接口。具体代码如下:

                package com.singleton.lazy;

                        public class Singleton {     

                        private static Singleton singleton;

                        //私有化构造方法

                        private Singleton (){

                        }

                        //提供公有化访问点

                        public Singleton getSingleton(){  

                                if(singleton==null){   //判断是对象否存在

                                    singleton=new Singleton();  

                                }  

                                return singleton;  

                      }

                }


该类将构造器设为private,则只有该类内部可以通过new创建实例,同时对外提供getSingleton()方法,调用该方法返回一个实例。(若实例未创建,则创建,创建后始终返回该实例) 此种方式在需要该类实例时才会创建可以称之为延迟实例化的方式(也称为懒汉模式)。另外重要的是,此种方法是非线程安全的。 试想若有2个线程同时到达 if(singleton==null)的判断中,并且都得到true,则就会产生两个实例,破坏单例模式的约束。

若想在多线程环境中应用单例模式,还需要对刚才的方法加以改变,将创建的实例看做共享的资源,当需要创建资源时加锁控制访问,操作完成后释放锁。

            

                package com.singleton.lazy;

                 

                public class Singleton2 {

                        private volatile static Singleton2 singleton;  

                        private Singleton2(){

                          

                        }  

                    public static Singleton2 getSingleton(){  

                       if(singleton==null){  //检查实例,若未创建进入同步块  

                            synchronized(Singleton.class){

                                     //同步块开始  

                                     if(singleton==null){ //进入同步块后再判断一次,防止出现2个线程同时通过第一次检                                              查的情况

                                          singleton= new Singleton2();  

                                     }

                            } //同步块结束  

                        }

                        return singleton;

                    }  

                }


volatile 的意思就是:告诉虚拟机,对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。 Singleton= new Singleton2()这句话不是原子操作,其主要包含3步:

1. Singleton2分配空间;
2. 初始化Singleton2的构造函数;
3. 将分配的空间地址返回给实例。

java编译器允许处理器乱序执行以提高执行效率,因此在实际执行中可能是1-2-3,也可能是1-3-2。若是1-3-2,若当线程1执行完3后轮到线程2执行,此时线程1由于执行了3singleton已不为空,而未执行构造函数等操作,因此得到的为不完整的实例,线程2使用该实例时就会出错。


二.初始实例化(饿汉模式)

以上使用线程加锁的方式可以解决多线程的方式,不过有些麻烦,还要考虑性能的一些影响。JVM可以保证一个类只被加载一次,因此可以考虑下面的方法

                package com.singleton.lazy;

                 

                public class Singleton {

                        private Singleton(){}

                        private static Singleton singleton = new Singleton();  

                        public Singleton getSingleton(){  

                                if(singleton==null){  

                                        singleton = new Singleton();  

                                }  

                                return singleton;  

                        }  

                }


此种方法在类被初次记载时即初始化了该类实例,不存在线程安全问题。

饿汉式的缺点是类一加载就实例化,提前占用系统资源。



没有了

下一篇

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

«   2024年3月   »
123
45678910
11121314151617
18192021222324
25262728293031
网站分类
标签列表
最近发表
最新留言
网站收藏
    RainbowSoft Studio Z-BlogRainbowSoft Studio Z-Blog订阅本站的 RSS 2.0 新闻聚合html5创意