设计模式之单例模式

来源:互联网 发布:电脑怎么连接多重网络 编辑:程序博客网 时间:2024/05/07 05:40

什么是单例模式

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。

简单点说,就是只要一个就够了,多了就就浪费资源。比如一个宿舍有四个人,只有一个拖把,谁需要谁用即可,没必要每人都有一个。

我们在操作数据库的时候经常使用,service和dao,通常我们每次用户访问一次都要创建一个新的对象,用完销毁。而使用单例模式可以让一个对象为所有用户服务。


单例模式的特点


  1.单例类只能有一个实例。
  2.单例类必须自己创建自己的唯一实例。
  3.单例类必须给所有其他对象提供这一实例。

单例模式的作用

保证在Java应用程序中,一个类Class只有一个实例存在。

懒汉式(使用时才创建对象,不使用不创建)

1.普通单例

public class Singleton {private static Singleton single = null;private Singleton() {}public static Singleton getSingleton() {//如果当前的single对象为null 创建对象if (single == null) {single = new Singleton();}return single;}}


分析:

private修饰的single和构造方法(如果构造方法为public修饰  就不是单例模式了)。public修饰的getSingleton方法返回该类中的唯一实例。

ps:即使为私有的构造方法  也可以通过java反射机制来为其实例化 这里不考虑。

那么懒汉式方法真的好吗?仔细分析,如果在single未实例化之前,有两个线程同时访问该getSingleton方法会怎样呢(并发)?这样系统就会调用两次构造方法,

也就实例化了两次single对象。如果这样写单例模式 只会让别人认为我们仅仅是了解了单例模式,并没有深入思考。

这时候肯定该说了  我大JAVA语言有synchronized关键字,分分钟让你只有一个线程访问。

2.synchronized

public class Singleton {private static Singleton single = null;private Singleton() {}public static synchronized Singleton getSingleton() {//如果当前的single对象为null 创建对象if (single == null) {single = new Singleton();}return single;}}
分析:

使用synchronized的确很好的解决了线程并发的问题。但是有没有想过在每次使用synchronized也会浪费时间的。

虽然计算机的执行速度很快,但是久而久之   浪费的世间就很多了。我们只想加一次synchronized锁怎么办呢?

需要使用另外一个关键字volatile。

(小知识点:

volatile的作用是: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.

比如  

a=5;a=6;a=7;
编译器会对这三条语句优化  只执行最后一条语句,也只产生一条机器码。最后a=7.而使用volatile关键字,

则编译器会逐一的进行编译并产生相应的机器代码(产生条代码).

3.synchronized+双重检验

public class Singleton {//使用volatile关键字修饰private static volatile Singleton single = null;private Singleton() {}//双重检验的方法public static synchronized Singleton getSingleton() {//如果当前的single对象为null 创建对象if (single == null) {synchronized (Singleton.class) {if(single==null){single = new Singleton();}}}return single;}}
分析:

比上个代码更加节省时间。

并发情况运行分析:

1.线程1进入getSingleton方法。

2.由于single=null,线程1进入synchronized块,线程2执行。

3.线程2进入getSingleton方法

4.single=null,线程2试图进入synchronized块,当此时线程1在synchronized块,线程2进入阻塞,线程1执行

5.线程1:在synchronized块的if语句中由于single仍然等于null, 为single实例化。

6.线程1退出synchronized块并返回single实例,线程2执行

7.线程2进入synchronized块,并判断当前single是否等于null,

8.线程2:由于当前single不为null,退出synchronized块,由线程1创建的single实例返回为线程2


饿汉式(即使没有线程访问也会创建对象

public class Singleton {// 直接创建一个实例 并且只会创建一次private static final Singleton single = new Singleton();private Singleton() {}public static Singleton getSingleton() {// 返回已经创建好的实例return single;}}


分析:

定义了一个静态变量single ,并且只创建一次实例,线程安全,以后不再改变。缺点就是一开始就申请号 浪费了一点资源。

静态内部类

public class Singleton {private static class SingletonHolder {// 静态初始化 JVM保证线程安全private static final Singleton single = new Singleton();}private Singleton() {}public static Singleton getSingleton() {return SingletonHolder.single;}}
分析:

SingletonHolder类级内部类,和外部类没有联系。只有使用的时候才会被加载。线程安全。上上之选的方法、

虽然静态内部类已经很好了  但是人们总是有追求的   在Java1.5发行版之后,使用枚举能够实现单例

枚举实现单例也就成了最优秀的方法,因为它线程安全,简单,并且枚举也提供了序列化机制。

下面通过一个例子来了解把

枚举单例

class Singleton{private String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}}public enum EnumSingleton {//枚举属性  一般大写   SINGLETON;   private Singleton single;   //私有的构造方法   private EnumSingleton(){   single=new Singleton();   }   //获取器   public Singleton getSingleton(){   return single;   }   //使用方法   public static void main(String[] args) {   Singleton single=EnumSingleton.SINGLETON.getSingleton();   single.setMessage("枚举实现单例模式");   System.out.println(single.getMessage());   }}
运行结果:枚举实现单例模式

使用枚举单例能够提高别人对你水平的看法哦~



2 0