设计模式-单例模式(饿汉式及懒汉式的Java实现)

单例模式

单例模式在程序设计中使用的频率非常之高,其设计的目的是为了在程序中提供唯一一个对象(保证只被构造一次),例如写入日志的log对象,windows的任务管理器实现(只能打开一个)。这里主要介绍单例模式使用Java的实现(包括饿汉式及懒汉式)。

实现

这里使用Log类作为例子,Log对象需要在程序中只有一个对象且只初始化一次。

饿汉式

饿汉式的单例模式理解起来是比较容易的,就是在单例类加载的时候就初始化需要单例的对象。实现也比较容易。

public class Singleton{
    private static Log logObj = new Log();

    public static Log getInstance(){
        return logObj;
    }
}

懒汉式

如果logObj需要占用很大的内存,如果一开始就初始化logObj,那么会占用大量的内存。此时,有人就想,如果我在想用的时候再初始化Log类的对象,像懒汉一样,只有用到的时候再初始化,需要怎么设计呢?

实现一(非线程安全版本)


public class Singleton{
    private static Log logObj = null;

    public static Log getInstance(){
        if(logObj == null){
            logObj = new Log();
        }
        return logObj;
    }
}

实现二(线程安全版本)


public class Singleton{
    private static Log logObj = null;

    public static synchronized Log getInstance(){
        if(logObj == null){
            logObj = new Log();
        }
        return logObj;
    }
}

为了实现线程安全,这个版本的实现牺牲了一定的效率,如果logObj已经初始化,那么其他线程还需要同步的进入getInstance方法,会造成效率的损失。于是,有些人实现了下面的版本。

实现三(错误版本)

public class Singleton{
    private static Log logObj = null;

    public static Log getInstance(){
        if(logObj == null){
            synchronized(Singleton.class){
                if(logObj == null){
                    logObj = new Log();
                }
            }
        }
        return logObj;
    }
}

乍看起来上面的版本是没问题的,如果某个线程A发现logObj 还没初始化,那么就进入同步块初始化logObj,如果在这期间有其他线程B进入,那么线程B就会等待进入同步块,等待A 线程退出同步块,logObj 已经初始化了,B 线程进入同步块后发现logObj 不为null,退出同步块,不再初始化logObj 。 这样既实现了线程安全,又兼顾了效率,确实是很聪明的编码方式。但是问题来了,由于指令重排序的存在,会导致Log在完全初始化之前logObj就已经不为null。这样其他线程可能会得到未完全初始化的对象。

解决方法

  1. JDK1.5版本后扩展了volitile语义,可以保证上述代码的正确性,为此只要将logObj 声明为volitile即可(volitile之前只是保证内存的可见性而已)。
  2. 使用静态内部类。

加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。

并且jvm会保证类加载的线程安全问题,所以利用这个特性可以写出兼顾效率与保证线程安全的版本。

实现四(兼顾效率与线程安全的版本)

public class Singleton{
    static class LogHolder{
        static Log logObj = new Log();
    }

    public static Log getInstance(){
        return LogHolder.logObj;
    }
}

这样在Singleton类加载时,并不会加载LogHolder,也就不会初始化Log,如果有线程访问getInstance方法,那么jvm会首先加载LogHolder类,并保证初始化logObj,最后返回logObj

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-26 03:42:16

设计模式-单例模式(饿汉式及懒汉式的Java实现)的相关文章

java===单类设计模式之饿汉式与懒汉式

package cn.china; public class Single { public static void main(String[]args){ // S singles=S.getInstance(); // S singless=S.getInstance(); // System.out.println(singles==singless); Test tt=Test.getInstance(); Test ttt=Test.getInstance(); tt.setNum(1

单例设计模式之饿汉式与懒汉式

/* 设计模式:对问题行之有效的解决方式.其实它是一种思想. 1,单例设计模式. 解决的问题:就是可以保证一个类在内存中的对象唯一性. 必须对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性. 如何保证对象唯一性呢? 1,不允许其他程序用new创建该类对象. 2,在该类创建一个本类实例. 3,对外提供一个方法让其他程序可以获取该对象. 步骤: 1,私有化该类构造函数. 2,通过new在本类中创建一个本类对象. 3,定义一个公有的方法,将创建的对象返回. */ //饿汉式 class

Java---15---单例设计模式:---饿汉式和懒汉式

概念: 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.   单例模式有以下特点: 1.单例类只能有一个实例 2.单例类必须自己给自己创建自己的唯一实例 3.单例类必须给所有其他对象提供这一实例 饿汉式: /*饿汉式*/ class Single { private static final Single s = new Single(); private Single () {} public static Single getInstance() { return s

java学习之单例模式(饿汉式与懒汉式)

---恢复内容开始--- 设计模式:解决某一类问题最行之有效的方法 java中有23种设计模式 今天学习其中一种:单例设计模式:解决一个类在内存只存在一个对象 想要保证对象唯一. 1.为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象 2.还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象 3.为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式 这三部分用代码体现: 1.将构造函数私有化 2.在类中创建一个本类对象 3.提供一个方法可以获取到该对象 packag

单例设计模式之饿汉式(静态常量)

package com.waibizi; /** * 单例设计模式之饿汉式(静态常量) * 步骤 * 1.构造器私有化(防止new) * 2.类的内部创建对象 * 3.向外暴露一个静态的公共方法 getInstance * 4.代码实现 * @author 歪鼻子 * * *优点:这种写法比较简单,类加载的时候就完成了实例化.避免了线程同步问题 *缺点:类装载的时候就完成了实例化,如果从开始到至终都没使用过这个类,势必会造成资源的浪费 *结论:这种单例模式是可用的,可能会导致浪费(调用getIn

单例模式 饿汉式 ARC

有了前两篇的文章这里直接给出代码,这种方法不是纯粹的饿汉式,比较懒汉式代码会容易一点点,但是苹果官方不推荐,了解一下就好. 此时没有多线程的困扰,使用之前就创建一个单例对象,此时还没有线程.所以不需要加锁. static id _instance = nil; +(void)load{//该类加载之后load就会被自动调用, _instance = [[self alloc] init]; } alloc new 都会来到这里,所以在这里重写更合适. + (id)allocWithZone:(s

Java-Singleton(单例创建-饿汉式,懒汉式)

package com.easygo.singleton; /** * Java单例有两种方式,饿汉式和懒汉式,饿汉式是在对象创建之前加载,优先于对象,而懒汉式是在对象创建完成后调用对象的方法来创建对象 * ,了解JVM加载原理的都清楚,正真意义上的单例是饿汉式,在对象创建之前加载. * @author lx * */ public class Singleton { //饿汉式 public static Singleton singleton=null; static { singleton

单例设计模式之饿汉式(静态代码块)

package com.waibizi.demo02; /** * 单例设计模式之饿汉式(静态代码块) * 这种方式与饿汉式静态常量的方式是类似的,类装载的时候也有直接创建对象 * @author 歪鼻子 * */ @SuppressWarnings("all") public class Singleton_Pattern { public static void main(String[] args) { // TODO Auto-generated method stub } }

设计模式中饿汉式单例类和懒汉式单例类

单例模式的特点为: *单例类只有一个实例. *单例类必须自己创建自己的唯一实例. *单例类必须给所有其他对象提供这一实例. 饿汉式单例类: 而饿汉式单例类则在java语言中是最为简单的单例类,这是一个描述饿汉式单例类的类图的实现. 此类图中,此类已经将自己实例化. 源码为: package singleton; public class EagerSingleton { private static EagerSingleton instance=new EagerSingleton(); /*