java技术---单件/单例模式
程序员文章站
2024-03-12 11:38:32
...
1.确保一个类只有一个实例,自行实例化并向系统提供这个实例
(1)整个系统只需要拥有一个的全局对象,这样有利于协调系统整体的行为
(2)返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance())
(3)将该类的构造函数定义为私有方法
(4) 所谓单例,指的就是单实例,有且仅有一个类实例,这个单例不应该由人来控制,而应该由代码来限制,强制单例
(5)单例模式应用实例:
<1>网站的计数器,一般采用单例模式实现,否则难以同步
<2>应用程序的日志应用,一般都用单例模式实现
<3>Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源
<4>数据库连接池的设计/多线程的线程池的设计
<5> 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统
<6>HttpApplication 也是单位例的典型应用
2.单例模式分类:饿汉式,懒汉式,双重检测 ,静态内部类
(1)饿汉式单例模式:
<1>类加载时实例化一个对象给自己的引用
<2>单例实例在类装载时就构建,并保存在类中。(预先加载法)
<3>优点:线程安全;
在类加载的同时已经创建好一个静态对象,调用时反应速度快 ;
<4>缺点:资源效率不高,可能getInstance()永远不会执行到,
但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化
//饿汉式(推荐)
public class EHanDanli{
//定义私有的无参构造器,用于单例实例
private EHanDanli() {}
//此处定义类变量实例并直接实例化,在类加载的时候就完成了实例化并保存在类中
public static EHanDanli eh= new EHanDanli();
//定义公开方法,返回已创建的单例
public EHanDanli getInstance() {
return eh;
} }
(2)懒汉式单例模式:线程不安全
<1>单例实例在第一次被使用时再构建,延迟初始化
<2>优点:避免了饿汉式的那种在没有用到的情况下创建事例;
资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法
<3>缺点:在多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,
虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。
解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大
会降低性能,同步一个方法可能造成程序执行效率下降100倍。
public class LHanDanli {
//定义私有类变量来存放单例,私有的目的是指外部无法直接获取这个变量,而要使用提供的公共方法来获取
private static LHanDanli lh = null;
//定义私有构造器,表示只在类内部使用,亦指单例的实例只能在单例类内部创建
private LHanDanli(){}
/**
* 定义公开的方法来返回该类的实例,需要在第一次使用时生成实例,
*多个线程判断lh都为null时,在执行new操作时多线程会出现重复情况
*所以为了线程安全,使用synchronized关键字来确保只会生成单例
**/
public static synchronized LHanDanli getInstance(){
if(lh == null){
lh = new LHanDanli();}
return lh;}
(3)双重检测
<1> 使用双重加锁,保证getInstacne()只在第一次会使用同步
<2>优点:资源利用率高,不执行getInstance()就不被实例,可以执行该类其他静态方法
volatile关键字确保当变量被初始化成Singleton实例时,多个线程正确的处理变量
volatile保证了共享变量的可见性,一个线程对变量的操作其他线程会立马知晓,
不会出现还未初始化完成就被使用的情况
<3>缺点:第一次加载时反应不快,由于java内存模型一些原因偶尔失败
Java1.4中JVM虚拟机对于volatile关键字的实现会导致双重检查加锁失败,只能使用Java5或以上的版本
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton () {}
public static Singleton getInstance() {
if (uniqueInstacne == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}}}
return uniqueInstance; }}
(4)静态内部类
<1>优点:资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法
<2>缺点:第一次加载时反应不够快
public class Test {
private Test() {}
private static class SingletonHelp {
static Test instance = new Test();}
public static Test getInstance() {
return SingletonHelp.instance;}}
3.总结:
(1)一般采用饿汉式:java中饿汉式性能优于懒汉式,c++中一般使用懒单例模式
(2)若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测
(3)单件模式中多线程情况下重复创建对象问题的处理办法:一般采用双重检测
(4)单例模式必须具备的3个元素:
<1>私有静态属性,用于存取类的唯一实例
<2>公共静态方法,用于提供对该唯一实例的存取访问,如果实例未创建,则创建该实例
<3>用于限制类再次实例化的方式。通常使用私有构建函数的方式来实现