1:懒汉的设计模式,在第一次调用的时候才完成相关的初始化操作

懒汉式是典型的时间换空间,就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间

package com.xiaohao.test;

/**
* 使用懒汉模式创建一个单例模式
* @author lenovo
*
*/
public class Singleton {
private static Singleton instance=null;
/**
* 返回或者创建相关的单例实例
* @return
*/
public static synchronized Singleton getInstance(){//使用同步方法保证线程安全
if(instance==null){
instance=new Singleton();
}
return instance;
}
/**
* 一个私有的构造方法,使外部的对象不能new相关的实例,这个尤其要注意,一定要提供默认的私有化的方法去覆盖默认的构造方法

* 否则的话,如果用户直接去new一个对象的话,就无法保证单例了~~~
*/
private Singleton(){}
}

2:饿汉的设计模式,在初始化类的过程中就会完成相关实例的初始化,一般认为这种方式要更加安全些

饿汉式是典型的空间换时间,当类装载的时候就会创建类的实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断,节省了运行时间。

package com.xiaohao.test;

/**
* 使用饿汉模式创建一个单例 模式
* @author lenovo
*
*/
public class Singleton {

//这个内部的单例仅仅用于内部访问,在初始化相关类的时候,就完成了相关单例类的初始化
//同时使用final修饰符修饰,一旦初始化值之后,不允许修改相关的值,这样也就实现了系统中的唯一
private static final Singleton instance=new Singleton();

/**
* 返回或者创建相关的单例实例
* @return
*/
public static Singleton getInstance(){
return instance;
}

/**
* 一个私有的构造方法,使外部的对象不能new相关的实例,这个尤其要注意,一定要提供默认的私有化的方法去覆盖默认的构造方法

* 否则的话,如果用户直接去new一个对象的话,就无法保证单例了~~~
*/

private Singleton(){}

}

此外还有一个比较给力的实现单例的方式,推荐大家使用这种方式:

Google公司的工程师Bob Lee写的新的懒汉单例模式
public class Singleton {

/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
*/

static class SingletonHolder {

/**
* 静态初始化器,由JVM来保证线程安全
*/

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

  
在加载singleton时并不加载它的内部类SingletonHolder,而在调用getInstance()时调用SingletonHolder时才加载SingletonHolder,从而调用singleton的构造函数,实例化singleton,从而达到lazy loading的效果。

3:双重锁的设计模式,实现在多线程下,相关性能的提高,尤其避免懒汉模式中,每次获取实例的时候都需要线程同步的问题

双重锁的主要目的是解决每次获取实例的时候都需要进行线程等待,只有在第一次实例化时,才启用同步机制,提高了性能。

提示:由于volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高。因此一般建议,没有特别的需要,不要使用。也就是说,虽然可以使用“双重检    查加锁”机制来实现线程安全的单例,但并不建议大量采用,可以根据情况来选用。

package com.xiaohao.test;

/**
* 使用双重锁模式创建一个单例模式
* @author lenovo
*
*/
public class Singleton {
private static Singleton instance=null;
/**
* 返回或者创建相关的单例实例
* @return
*/
public static Singleton getInstance(){
if(instance==null)
{
 synchronized (Singleton.class){//需要注意的是,这里锁住的是类,一旦加上这个类锁之后,所有和这个类相关的操作(包括这个类的所有属性和方法)都需要进行相关的等待

if(instance==null){

instance=new Singleton();

}
}
}
return instance;
}
/**
* 一个私有的构造方法,使外部的对象不能new相关的实例,这个尤其要注意,一定要提供默认的私有化的方法去覆盖默认的构造方法

* 否则的话,如果用户直接去new一个对象的话,就无法保证单例了~~~
*/
private Singleton(){}
}

}

这个方法表面上看起来很完美,你只需要付出一次同步块的开销,但它依然有问题。除非你声明instance变量时使用了volatile关键字。没有volatile修饰符,可能出现Java中的另一个线程看到个初始化了一半的instance的情况,但使用了volatile变量后,就能保证先行发生关系(happens-before relationship)。对于volatile变量_instance,所有的写(write)都将先行发生于读(read),在Java 5之前不是这样,所以在这之前使用双重检查锁有问题。现在,有了先行发生的保障(happens-before guarantee),你可以安全地假设其会工作良好。另外,这不是创建线程安全的单例模式的最好方法,你可以使用枚举实现单例模式,这种方法在实例创建时提供了内置的线程安全。另一种方法是使用静态持有者模式(static holder pattern),这种方式就是开始的饿汉模式,所以说饿汉模式相对来说比较安全一些。

package com.xiaohao.test;

/**
* 使用双重锁模式创建一个单例模式,双重锁模式下的进一步优化
* @author lenovo
*
*/
public class Singleton {
//注意这里面的volatile 这个关键字,它的主要作用是写(write)优于读(read),前提是jdk的版本要不低于jdk5.0
private volatile static Singleton instance=null;
/**
* 返回或者创建相关的单例实例
* @return
*/
public static Singleton getInstance(){
if(instance==null)
{
synchronized (Singleton.class){//需要注意的是,这里锁住的是类,一旦加上这个类锁之后,所有和这个类相关的操作(包括这个类的所有属性和方法)都需要进行相关的等待

if(instance==null){

instance=new Singleton();

}
}
}
return instance;
}
/**
* 一个私有的构造方法,使外部的对象不能new相关的实例,这个尤其要注意,一定要提供默认的私有化的方法去覆盖默认的构造方法

* 否则的话,如果用户直接去new一个对象的话,就无法保证单例了~~~
*/
private Singleton(){}
}

4:使用枚举实现单例模式,这种方法在实例创建时提供了内置的线程安全

package com.xiaohao.test;

/**
* 使枚举的方法创建一个单例类
* @author lenovo
*
*/
public enum Singleton {
INSTANCE;// 使用枚举类的方法创建一个单例,据说这是目前位置,无论是多线程还是,防止反射创建
//相关对象最有用的方法,推荐使用
}

单元素的枚举类型已经成为实现Singleton的最佳方法。用枚举来实现单例非常简单,只需要编写一个包含单个元素的枚举类型即可。使用enum关键字来实现单例模式的好处是这样非常简洁,并且无偿地提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。使用枚举来实现单实例控制会更加简洁,而且无偿地提供了序列化机制,并由JVM从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式。——来自《Effective Java》

***知识补充(拷贝的)----针对谷歌那个工程师的方法:

 这个模式综合使用了Java的类级内部类和多线程缺省同步锁的知识,很巧妙地同时实现了延迟加载和线程安全。

  1.相应的基础知识

  •  什么是类级内部类?

  简单点说,类级内部类指的是,有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类。

  类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。

  类级内部类中,可以定义静态的方法。在静态方法中只能够引用外部类中的静态成员方法或者成员变量。

  类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载。

  •  多线程缺省同步锁的知识

  大家都知道,在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制。但是在某些情况中,JVM已经隐含地为您执行了同步,这些情况下就不用自己再来进行同步控制了。这些情况包括:

  1.由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时

  2.访问final字段时

  3.在创建线程之前创建对象时

  4.线程可以看见它将要处理的对象时

  2.解决方案的思路

  要想很简单地实现线程安全,可以采用静态初始化器的方式,它可以由JVM来保证线程的安全性。比如前面的饿汉式实现方式。但是这样一来,不是会浪费一定的空间吗?因为这种实现方式,会在类装载的时候就初始化对象,不管你需不需要。

  如果现在有一种方法能够让类装载的时候不去初始化对象,那不就解决问题了?一种可行的方式就是采用类级内部类,在这个类级内部类里面去创建对象实例。这样一来,只要

不使用到这个类级内部类,那就不会创建对象实例,从而同时实现延迟加载和线程安全。

****最后需要注意一点,上面除了使用枚举类的方法外,其它的方法都可以通过java的反射机制创建相关的对象,即使使用private 重写了相关的构造方法~~

单例模式总结(Java版)的更多相关文章

  1. 你真的会写单例模式吗-------Java实现

    转载: 你真的会写单例模式吗--Java实现 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模式,还真得费一番脑筋.本文对Java中常见的单例模式写法做了一个总结,如有错漏 ...

  2. 网页爬虫的设计与实现(Java版)

    网页爬虫的设计与实现(Java版)     最近为了练手而且对网页爬虫也挺感兴趣,决定自己写一个网页爬虫程序. 首先看看爬虫都应该有哪些功能. 内容来自(http://www.ibm.com/deve ...

  3. [转] 你真的会写单例模式吗——Java实现

    你真的会写单例模式吗——Java实现 原文:http://www.tuicool.com/articles/MBrUfy6 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模 ...

  4. pureMVC java版搭建流程

    转自:http://blog.csdn.net/sutaizi/article/details/6588004 pureMVC 是一个轻量级的框架 它在 flex中非常流行(和cairngorm差不多 ...

  5. ArcGIS Server 10 Java 版的Rest服务手动配置方法

    Java版的Manager中发布的服务默认只发布了该服务的SOAP接口,而REST接口需要用户在信息服务器,如Tomcat. Apache.WebLogic等中手工配置.由于在Java版的Server ...

  6. PetaPojo —— JAVA版的PetaPoco

    背景 由于工作的一些原因,需要从C#转成JAVA.之前PetaPoco用得真是非常舒服,在学习JAVA的过程中熟悉了一下JAVA的数据组件: MyBatis 非常流行,代码生成也很成熟,性能也很好.但 ...

  7. 【转载】java版打字练习软件

    网上找到一个java版的打字的游戏 import java.applet.Applet; import java.applet.AudioClip; import java.awt.Dimension ...

  8. 微博地址url(id)与mid的相互转换 Java版

    原理: 新浪微博的URL都是如:http://weibo.com/2480531040/z8ElgBLeQ这样三部分. 第一部分(绿色部分)为新浪微博的域名,第二部分(红色部分)为博主Uid,第三部分 ...

  9. JCEF3——谷歌浏览器内核Java版实现(一):使用jawt获取窗体句柄

    前言 最近一段时间研究谷歌浏览器内核.谷歌浏览器内核一直开源,并维护更新,它的开源项目中内核更新速度和Chrome浏览器版本更新进度一样!而且它不同于WebKit(值得一题的是谷歌浏览器已不使用Web ...

  10. Selenium关键字驱动测试框架Demo(Java版)

    Selenium关键字驱动测试框架Demo(Java版)http://www.docin.com/p-803493675.html

随机推荐

  1. 【转】No JVM could be found on your system解决方法

    原文网址:http://my.oschina.net/liusicong/blog/324964 在安装android studio时,报错: Error launching android Stud ...

  2. SQLlite(WebSQL)如何排序并分页查询(SQLlite语法)

    SELECT * FROM Table ORDER BY ID DESC Limit 10,9 limit语义:跳过10行,取9行 参考: SQLite的limit用法   如果我要去11-20的Ac ...

  3. OutputCache缓存各参数的说明

    Duration 缓存时间,以秒为单位,这个除非你的Location=None,可以不添加此属性,其余时候都是必须的. Location Location当被设置为None时,其余的任何设置将不起作用 ...

  4. IOCP模型

    IOCP http://blog.csdn.net/zhongguoren666/article/details/7386592 Winsock IO模型之IOCP模型 http://blog.csd ...

  5. 查看系统或者Jmeter的Properties

    工作台-非测试元件-Property Display,可以显示系统或者Jmeter的Properties

  6. [Web API] 如何让 Web API 统一回传格式以及例外处理[转]

    [Web API] 如何让 Web API 统一回传格式以及例外处理 前言 当我们在开发 Web API 时,一般的情况下每个 API 回传的数据型态或格式都不尽相同,如果你的项目从头到尾都是由你一个 ...

  7. Hadoop的partitioner、全排序

    按数值排序 示例:按气温字段对天气数据集排序问题:不能将气温视为Text对象并以字典顺序排序正统做法:用顺序文件存储数据,其IntWritable键代表气温,其Text值就是数据行常用简单做法:首先, ...

  8. Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF

    在实时渲染中Physically-Based Rendering(PBR)中文为基于物理的渲染它能为渲染的物体带来更真实的效果,而且能量守恒 稍微解释一下字母的意思,为对后文的理解有帮助,从右到左L为 ...

  9. 选择学习Pomelo

    我之前的项目都是基于http做网络通信,但是做多玩家同时对战的游戏,http短连接不支持服务器的push是个问题,这样客户端就没办法收到服务器的消息. 最简单的方法是定时发起request询问服务器, ...

  10. CentsOS7 网络自动启动

    虚拟机中安装完成CentOS7后,网络总是需要手工启动才可使用,设置为自动连接的方式如下: cd /etc/sysconfig/network-scripts/ls #找到类似的文件:ifcfg-et ...