`

Singleton 两种实现方法的异同

 
阅读更多

注意:红色、蓝色是我认为比较重要的

首先了解一下Singleton模式通常的两种表现形式:
第一种形式:

public class Singleton { 
    
private Singleton(){} 
    
//在自己内部定义自己一个实例,是不是很奇怪? 
    
//注意这是private 只供内部调用 
    private static Singleton instance = new Singleton(); 
    
//这里提供了一个供外部访问本class的静态方法,可以直接访问 
    public static Singleton getInstance() { 
       
return instance; 
    }
}

第二种形式:

public class Singleton { 
   private static Singleton instance = null
   public static synchronized Singleton getInstance() { 
      //这个方法比上面有所改进,不用每次都进行生成对象,只是第一次 
      //使用时生成实例,提高了效率! 
      if (instance==null) instance=new Singleton(); 
      return instance; 
   } 
}

   
使用Singleton.getInstance()可以访问单态类。 
   上面第二中形式就是lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。 
   注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例,但会严重影响性能。
如何实现Lazy Singleton?方法是利用Java的ClassLoader即时装载特性,使用一个SingletonHolder实现:

static class SingletonHolder {
      static Singleton instance = new Singleton();
  }
public static Singleton getInstance() {
      return SingletonHolder.instance;
  }

  这里利用Java ClassLoader特性,在第一次加载SingletonHolder 的时候初始化实例,并且保证了没有多线程并发问题。当CLR加载class Singleton的时候,因为Singleton没有static variables需要被初始化,所以Singleton的初始化其实什么也没做。而对static class SingletonHolder 来说,直到它被执行的时候才会被初始化。而static class SingletonHolder 只有载Singleton.GetInstance()被执行的时候才会执行到。当第一次调用GetInstance()的时候 CLR才会加载和初始化SingletonHolder 这个class。对于SingletonHolder class的初始化就是对static variable Instance的初始化。而Instance的初始化就是执行Singleton的private constructor方法。


   那么为什么只有使用synchronized关键字才可以达到单态的目的呢?synchronized到底有什么含义呢?
   synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。
1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:

public synchronized void accessVal(int newVal); 

   synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。 
   在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。 
   synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。
2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:

synchronized(syncObject) { 
   //允许访问控制的代码 

synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。


对synchronized(this)的一些理解

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

五、以上规则对其它对象锁同样适用

分享到:
评论

相关推荐

    java面试宝典

    237、触发器分为事前触发和事后触发,这两种触发有和区别。语句级触发和行级触发有何区别。 56 238、EJB容器提供的服务 56 239、EJB的角色和三个对象 56 240、EJB的几种类型 56 241、bean 实例的生命周期 56 242、...

    二十三种设计模式【PDF版】

    可扩展的使用 JDBC针对不同的数据库编程,Facade提供了一种灵活的实现. 设计模式之 Composite(组合) 就是将类用树形结构组合成一个单位.你向别人介绍你是某单位,你是单位中的一个元素,别人和你做买卖,相当于 和...

    超级有影响力霸气的Java面试题大全文档

     Session Bean 还可以再细分为 Stateful Session Bean 与 Stateless Session Bean ,这两种的 Session Bean都可以将系统逻辑放在 method之中执行,不同的是 Stateful Session Bean 可以记录呼叫者的状态,因此通常...

    JAVA相关的面试大全

    - **EntityBean**:持久化对象,分为CMR(容器管理关系)和BMP(Bean管理持久化)两种类型。 #### 9. Collection和Collections的区别。 - `Collection`是Java集合框架的根接口,所有集合类都直接或间接实现它。 - ...

    最新Java面试宝典pdf版

    1、用两种方式根据部门号从高到低,工资从低到高列出每个员工的信息。 91 2、列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序 91 3、存储过程与触发器必须讲,经常被面试到? 92 4、数据库...

    Java面试宝典-经典

    1、用两种方式根据部门号从高到低,工资从低到高列出每个员工的信息。 91 2、列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序 91 3、存储过程与触发器必须讲,经常被面试到? 92 4、数据库...

    java面试题大全(2012版)

    1、用两种方式根据部门号从高到低,工资从低到高列出每个员工的信息。 91 2、列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序 91 3、存储过程与触发器必须讲,经常被面试到? 92 4、数据库...

    java面试宝典2012

    1、用两种方式根据部门号从高到低,工资从低到高列出每个员工的信息。 99 2、列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序 100 3、存储过程与触发器必须讲,经常被面试到? 101 4、...

    Java面试宝典2012版

    1、用两种方式根据部门号从高到低,工资从低到高列出每个员工的信息。 91 2、列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序 91 3、存储过程与触发器必须讲,经常被面试到? 92 4、...

    Java面试宝典2012新版

    1、用两种方式根据部门号从高到低,工资从低到高列出每个员工的信息。 91 2、列出各个部门中工资高于本部门的平均工资的员工数和部门号,并按部门号排序 91 3、存储过程与触发器必须讲,经常被面试到? 92 4、数据库...

    Ruby程序设计高级教程

    - **与Python的比较**:通过对比Ruby和Python这两门语言,帮助读者理解它们之间的异同,以及各自适用的场景。 #### 二、Ruby编程环境 - **安装过程**: - Windows系统下的安装步骤和注意事项。 - Linux环境下...

    浅谈Spring单例Bean与单例模式的区别

    本文主要介绍了Spring单例Bean与单例模式的区别,通过对比两者的定义、实现机制和应用场景,帮助读者更好地理解这两种概念的异同。 一、单例模式的定义和实现 单例模式是一种创建型设计模式,它的主要特点是确保在...

    spring-interview

    下面我们将深入探讨两个关键知识点:单例(Singleton)与原型(Prototype)范围的Bean,以及Singleton范围Bean与Singleton设计模式之间的联系。 **1. 单例(Singleton)范围的Bean** 在Spring框架中,Bean的生命...

    改造易买网布局图.txt

    2. **静态工厂方法与动态工厂方法的异同** - **静态工厂方法**:通过静态方法直接实例化对象,适用于对象创建过程简单的情况。 - **动态工厂方法**:先创建工厂对象,然后通过该对象实例化具体的目标对象。这种...

    面向对象重点复习

    - **简单工厂**只提供一个工厂类,而其他两种则可以有多个工厂类。 - **工厂方法模式**和**抽象工厂模式**更侧重于系统的扩展性和灵活性。 ##### 5. 替换的转换。 - **定义**: - 替换的转换是一种设计模式,...

    net学习笔记及其他代码应用

    10.求以下表达式的值,写出您想到的一种或几种实现方法: 1-2+3-4+……+m [Page] 答: int Num = this.TextBox1.Text.ToString() ; int Sum = 0 ; for (int i = 0 ; i ; i++) { if((i%2) == 1) { Sum += i ; ...

    java面试800题

    Q0058 一个Java抽象类声明了一个方法并会抛出一个异常,问继承这个抽象类的子类,实现了这个方法,这个方法声明是不是一定要抛出一模一样的异常,可不可以不抛,或者抛出的异常比抽象类的异常范围大,或者小?...

    design-pattern.rar

    创建型模式涉及到对象的创建,如单例(Singleton)、工厂方法(Factory Method)和建造者(Builder)等,它们处理如何以及何时创建对象的问题。结构型模式关注类和对象的组合,例如适配器(Adapter)、装饰器...

Global site tag (gtag.js) - Google Analytics