Java模式之单例模式

单例模式是指某个类有唯一的实例。
最常见的获取单例的方法有两种:饿汉式和懒汉式。

懒汉式单例模式:

public class Single1 {
    private static Single1 single1;
    private Single1(){}
    public static Single1 getInstance(){
    if (single1 == null){
    single1 = new Single1();
    }
    return single1;
  }
}

懒汉式单例模式,意思是调用getInstance()后才会生成对象,并返回对象,即需要的时候才会生成一个对象。
注意:getInstance()方法为static修饰的静态方法,使得方法属于类,通过[Single1.]便可调用getInstance(),避免其他类中创建Single1对象,另外private修饰的构造方法表明,只能在该类中生成对象。
懒汉式单例模式的特点是延迟加载,在需要该对象的时候才会生成对象,节省了不必要的空间;但该模式也存在一个致命的缺点,后面会讲到。

饿汉式单例模式:

public class Single2 {
  private static final Single2 SINGLE2 = new Single2();
  private Single2(){}
  public static Single2 getInstance(){
  return Single2.SINGLE2;
  }
}

饿汉式单例模式,意思是类加载就会立马生成一个对象,为了保证只能生成一个该类的对象,所以用关键字final修饰,即不可变。当需要该对象的时候,调用getInstance()方法即可返回该唯一的对象。
饿汉式单例模式的特点:饿汉式故名思议好比处于饥饿状态,类加载后立马生成该类的实例,不管需不需要;这容易造成空间的浪费,相比懒汉式单例,饿汉式单例不可用。

饿汉式单例模式还可以换一种方法来实现,即便不推荐使用;饿汉式静态模块单例模式:

public class Single3 {
  private Single3(){}
  private static Single3 single3;
  static
  {
  single3 = new Single3();
  }
  public static Single3 getInstance(){
  return single3;
  }
}
饿汉式静态模块单例模式的本质跟上面的饿汉式单例模式一样,只不过把直接生成单例的过程放到了静态代码块,即在类加载的过程中会执行静态代码块的内容,即生成了single3实例。
注意:这里的single3引用没有final关键字,因为一个类加载只会执行一次静态代码块,所以能确保single3的实例是唯一的。

上面说到懒汉式单例模式,即Single1有一个致命的缺点,我们通过代码来说明:

public class Client {
    static Single1 single1;
    public static void main(String[] args) {
    for (int i = 0; i < 10; i++){
    Runnable runnable = new Runnable(){
    public void run() {
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
  }
  single1 =Single1.getInstance();
  System.out.println(single1);
  }
  };
    new Thread(runnable).start();
    }
  }
}

代码含义:把懒汉式单例模式放到多线程下执行。
Thread.sleep(2000)是让当前执行单例模式的线程休眠2秒,让线程不那么快执行完,便于看到效果。
运行后的某一种结果:

[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

很明显,10个线程调用懒汉式单例模式后返回的对象居然有4个,这与单例模式的含义相违背,表明懒汉式单例模式在多线程下不可行,这是懒汉式单例模式致命的缺点。
分析执行过程可知,当线程1在执行if(single1 == null)后执行singe1 = new Single1()生成对象的同时,线程2也正好在判断if(single1 == null),由于线程1的对象还没有生成,所以线程2的判断为true,便进一步执行single1 = new Single1(),所以便会生成多个Single1对象。

为了解决这个问题,我们自然想到synchronized关键字,即在获取single1对象的方法getInstance()上加锁,使其成为

同步方法:

public class Single1 {
  private static Single1 single1;
  private Single1(){}
  public static synchronized Single1 getInstance(){
  if (single1 == null){
  single1 = new Single1();
  }
  return single1;
  }
}
同步方法getInstance()能保证每次只有一个线程进入方法内部,这样便能保证单例。
同步方法的特点:通过synchronized关键字使得线程获得Single1类的内置锁从而保证每次只有一个线程执行getInstance()。进一步分析执行过程:线程1执行方法getInstance时获取Single1的内置锁,此时线程2过来想要执行方法getInstance,发现方法所属类的锁已经被线程1占有,所以线程2被阻塞,接着线程3,线程4…继续被阻塞,这样导致的结果就是执行的效率非常低。我们想想,其实只有线程1进入方法getInstance生成实例后,方法2、3、4…都不需要生成实例,因此也就没必要阻塞后面的线程,所以可以缩小同步的范围,即把从同步方法变成同步代码块。

双重检查的单例模式:

public class Single1 {
    private static volatile Single1 single1;
    private Single1(){}
    public static Single1 getInstance(){
    if (single1 == null){
    synchronized(Single1.class){
    if (single1 == null){
    single1 = new Single1();
    }
  }
}
  return single1;
  }
}
双重检查的单例模式把同步从方法级别移到方法内部,只对必要的代码块进行同步;注意这里有两个判空,所以称为双重检查。第一次判空是所有线程都会执行的,当线程1判空后,就会获取Single1类的内置锁,线程1则势必会执行single1 = new Single1(),生成single1实例;假如线程1在执行同步代码块的时候,线程2进入方法getInstance,第一次判空为true,此时Single1的内置锁被线程1占有,因此被阻塞,当线程1执行完后退出同步代码块释放Single1的内置锁,线程2就会进入同步代码块,此时若线程3进来,因为线程1已经生成single1对象,所以线程3的第一次判空为false,则线程3执行返回对象,线程2进行第二次判空同样为false,直接返回single1实例。后面的线程在第一个判空处便为false。
双重检查单例模式的特点就是线程安全,延迟加载,效率高,比较常用。
注意:声明single1对象时,使用了volatile关键字。volatile关键字可以保证single1对象的可见性和有序性;这是防止指令重排从而保证single1对象的唯一。

静态内部类的单例模式:

public class Single4 {
  private Single4(){

  }
  private static class Single4Inner{
  private static final Single4 SINGLE4 = new Single4();
  }
  public static Single4 getInstance(){
  return Single4Inner.SINGLE4;
  }
}

静态内部类的单例模式与饿汉式单例模式有点类似,唯一的不同在于,饿汉式单例模式中单例对象是随着Single2类加载而生成,而静态内部类单例模式则通过静态内部类产生单例对象,其利用静态内部类不会随着外部类的加载而加载的特性使得当getInstance方法被调用后Single4Inner类才会被加载,从而生成SINGLE4对象,同时用static和final修饰,保证只会生成一个SINGLE4对象,保证了其线程的安全。

枚举类单例模式:

public enum Single5 {
  SINGLE_5;
  public Single5 getInstance() {
  return SINGLE_5;
  }
}
枚举类单例模式是最实用的一种单例模式。枚举类本身带有私有的构造方法,而每个枚举对象都是static和final修饰的对象,表明对象只能被实例化一次,所以在枚举实例的时候就会产生单例。

以上是所有产生单例的方法,总结有:饿汉式单例,懒汉式单例,饿汉式静态模块单例,同步方法单例,双重检查单例,静态内部类单例以及枚举类单例。

2 单例模式的原理
单例模式能够保证一个类仅有一个实例,并提供一个访问它的全局访问点。

3 单例模式的特点
故名思议,单例模式表明某个类只有一个实例。

原文地址:https://www.cnblogs.com/fplblog/p/11100182.html

时间: 2024-10-22 13:43:52

Java模式之单例模式的相关文章

java模式:深入单例模式

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://devbean.blog.51cto.com/448512/203501 在GoF的23种设计模式中,单例模式是比较简单的一种.然而,有时候越是简单的东西越容易出现问题.下面就单例设计模式详细的探讨一下. 所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在.就像是Java Web中的application,也就是提供了一个全局变量,用处相当广泛,比如保存全局数据,实

java设计模式之单例模式随笔

Java模式之单例模式: 凡是看单例模式,都会看到两种经典的结构: 饿汉式 1 public class EagerSingle { 2 private static EagerSingle instance = new EagerSingle(); 3 public static EagerSingle getInstance() { 4 return instance; 5 } 6 } 之所以称为饿汉式,是因为在类被加载的时候,静态变量 instance 会直接被初始化. 2. 懒汉式 1

Java中的GOF23(23中设计模式)--------- 单例模式(Singleton)

Java中的GOF23(23中设计模式)--------- 单例模式(Singleton) 在Java这这门语言里面,它的优点在于它本身的可移植性上面,而要做到可移植的话,本身就需要一个中介作为翻译工作,以达到本地和Java的统一,但是就这点而言就相当的消耗资源,所以就Java程序员需要不断的去优化自己的代码.今天所研究的单例模式就是在这样的条件下产生的, 所谓单例模式,就是只有一个实例,在堆里面只有一个.假如我们的实例,就需要一个,但是会多次用到,这样的话就会出现很尴尬的问题. 比如: Win

java中单态模式或单例模式(Singleton)有什么意义?

8.单态模式或单例模式(Singleton) (视频下载) (全部书籍)单态模式有什么用呢?想一下Adobe Photoshop ,处理两张图,会启动两个photoshop吗?多耗费内存呀! ( Consider Adobe or oracle, process two images with two adobes?),所以单态模式在公司编程是非常重要的.有很多场合都要求,对象只能存在一个,多了的话就太耗费资源.(马克-to-win) class Photoshop {/* 通过调试发现写成 s

(九)JAVA设计模式之单例模式

JAVA设计模式之单例模式 一.单例模式的介绍 Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点.     全局对象和Singleton模式有本质的区别,因为大量使用全局对象会使得程序质量降低,而且有些编程语言根本不支持全局变量.最重要的是传统的全局对象并不能阻止一个类被实例化多次. 二.单例模式的特点 单例类只能有一个实例 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例.

JAVA中的单例模式(采用单例模式定义的类)(转)

1     单例(Singleton)模式:单例模式确保某一个类只有一个 实例,而且该类只能是自己 实例化自己并向其他类公开 这个实例的对象创建 模式 采用单例模式的类:根据单例模式知道其要满足以下三点 1. 确保某一个类只有一个实例 2. 而且自己实例化 3. 并向其他类提供这个实例类 . 2    确保以上三点的所采用的编程策略     * 把构造方法声明为Private.确保只能由自己创建,避免外部创建实例或者被子类继承从而创造额外实例:    * 定义一个私有静态的该类的实例作为该类的数

【JAVA设计模式】单例模式

在阎宏博士的<JAVA与模式>一书中开头是这样描述单例模式的: 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式的结构 单例模式的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例. 饿汉式单例类 public class EagerSingleton { private static EagerSingleton instance = new EagerSingle

java模式及其应用场景

最经典的java 23种设计模式及具体例子(转发) 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样.项目中合理的运用 设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问

java 设计模式之单例模式

--------2015-11-20 14:45:10 java设计模式之单例模式(Singleton): ---应用场合:只需要一个对象就可以了,例如一个朝代一个皇帝. ---作用:保证某个应用程序中某个实例有且只有一个.共同使用一个,节省资源. ---类型:饿汉模式,懒汉模式. 一.饿汉模式(类加载的时候就会实例化,线程安全) 1 package com.sun.singleton; 2 3 //饿汉模式 4 public class Singleton { 5 6 //将构造函数私有化,不