在Java中,单例有很多种写法,面试时,手写代码环节,除了写算法题,有时候也会让手写单例模式,这里记录一下单例的几种写法和优缺点。

  • 初级写法
  • 懒汉式
  • 饿汉式
  • 双锁检验
  • 内部类
  • 枚举式

1.初级写法

public class Singleton {

    private static Singleton singleton = null;

    public Singleton() {
} /**并发下会产生多个实例*/
public static Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}

上面这种写法,在并发环境下,会出现多个实例。

2.懒汉式

我们优化上面的代码,遇到并发,很容易想到加锁,把获取对象的方法加上关键字synchronized,这种写法称为懒汉式单例,如下:

public class BSingleton {

    private static BSingleton bSingleton;

    private BSingleton() {
} /**
* 整个方法锁住了,效率较低
* @return
*/
public synchronized static BSingleton getbSingleton(){
if(bSingleton == null){
bSingleton = new BSingleton();
}
return bSingleton;
}
}

懒汉式的特点是,用到这个实例时才去调用方法实例化。但是,我们把整个方法都同步了,效率很低下,我们可以继续优化,只在创建实例的地方加上同步,参考5双锁检验。

3.饿汉式

饿汉式的特点是:类在加载时就直接初始化了实例。即使没用到,也会实例化,因此,也是线程安全的单例模式。

public class ESingleton {

    /**类在加载的时候直接进行初始化*/
private static final ESingleton ESINGLETON = new ESingleton(); private ESingleton() {} /**对外暴露唯一接口 提供单例对象*/
public static ESingleton geteSingleton(){
return ESINGLETON;
}
}

4.双锁检验

双重非空判断,new对象前加一次锁。

volatile关键字,考虑的是,new关键字在虚拟机中执行时其实分为很多步骤,具体原因可以参考深入理解java虚拟机一书(考虑的是这个new关键字字节码执行时是非原子性的),而volatile关键字可以防止指令重排。

public class SynchronizedSingleton {

    /**volatile防止指令重排*/
private static volatile SynchronizedSingleton singleton; private SynchronizedSingleton() {
} /**只是在实例为空时才进行同步创建
* 为什么做了2次判断?
* A线程和B线程同时进入同步方法0
* 然后都在1位置处判断了实例为null
* 然后都进入了同步块2中
* 然后A线程优先进入了同步代码块2中(B线程也进入了),然后创建了实例
* 此时,如果没有3处的判断,那么A线程创建实例同时,B线程也会创建一个实例
* 所以,还需要做2次判断
* */
public static SynchronizedSingleton getInstance(){//
if(singleton == null){//
synchronized (SynchronizedSingleton.class){//
if(singleton == null){//
singleton = new SynchronizedSingleton();//
}
}
}
return singleton;
}
}

5.内部类

public class Singleton {

    private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
} private Singleton (){} public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

优点:由于静态内部类跟外部类是平级的,所以外部类加载的时候不会影响内部类,因此实现了lazy loading, 同时也是利用静态变量的方式,使得INSTANCE只会在SingletonHolder加载的时候初始化一次,从而保证不会有多线程初始化的情况,因此也是线程安全的。

6.枚举式

public enum Singleton{
INSTANCE;
public void whateverMethod() { }
}

这是知名书籍Java Effective推荐的单例实现方式,这种代码最简练,并且天生线程安全。

推广:一个好消息

同学,你造吗?阿里云和腾讯云已白菜价,云服务器低至不到300元/年。这里有一份云计算优惠活动列表,来不及解释了,赶紧上车!

Java单例模式的6种写法的更多相关文章

  1. Java 单例模式的七种写法

    Java 单例模式的七种写法 第一种(懒汉,线程不安全) public class Singleton { private static Singleton instance; private Sin ...

  2. 单例模式:Java单例模式的几种写法及它们的优缺点

    总结下Java单例模式的几种写法: 1. 饿汉式 public class Singleton { private static Singleton instance = new Singleton( ...

  3. java单例模式的几种写法比较

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  4. JAVA单例模式的几种写法

    /** * 单例模式懒汉式(双重检锁线程安全.JDK1.5之后) */ public class Singleton { private static volatile Singleton singl ...

  5. java 单例模式的几种写法

    一.懒汉式 public class Singleton{ private static Singleton instance = null; private Singleton(){} public ...

  6. Java设计模式之单例模式(七种写法)

    Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton { private static Singleto ...

  7. 单例模式的N种写法

    单例模式算是设计模式中最容易理解,也是最容易手写代码的模式了吧.但是其中的坑却不少,所以也常作为面试题来考.本文主要对几种单例写法的整理,并分析其优缺点.很多都是一些老生常谈的问题,但如果你不知道如何 ...

  8. java设计模式之单例模式(几种写法及比较)

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  9. Java:单例模式的七种写法(转载)

    第一种(懒汉,线程不安全): package Singleton; /** * @echo 2013-10-10 懒汉 线程不安全 */ public class Singleton1 { priva ...

随机推荐

  1. html5--6-9 CSS选择器6--伪类选择器

    html5--6-9 CSS选择器6--伪类选择器 实例 @charset="UTF-8"; /*:root{background: green}*/ /*li:first-chi ...

  2. 【扬中集训DAY1T1】 微信群

    [题目链接] 点击打开链接 [算法] 对问题稍加分析后,发现其实要求的就是 : C(N,K) + C(N,K+1) + C(N,K+2) + ... + C(N,N) 因为N最大10^9,K最大10^ ...

  3. Python的多进程锁的使用

    很多时候,我们需要在多个进程中同时写一个文件,如果不加锁机制,就会导致写文件错乱 这个时候,我们可以使用multiprocessing.Lock() 我一开始是这样使用的: import multip ...

  4. linux--安装phpcurl扩展

    在UBUNTU中直接用APT包管理工具安装: apt-get install curl libcurl3 libcurl3-dev php5-curl 安装好后重启Apache服务器就行了,如果还是不 ...

  5. Code:NFine框架

    ylbtech-Code:NFine框架 1.返回顶部 1.         2. 2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   作者:ylbtech出 ...

  6. Code-NFine:jqgrid 数据绑定

    ylbtech-Code-NFine:jqgrid 数据绑定 1. jqgrid 基本列展示返回顶部 1. 1.1..cshtml $(function () { gridList(); }) fun ...

  7. 泛型Class<T>和 T. <T>

    private T product; private Class<T> product; 这两个有什么区别呢,查了资料才知道,单独的T 代表一个类型 而 Class<T>代表这 ...

  8. YARN(MapReduce 2)运行MapReduce的过程-源码分析

    这是我的分析,当然查阅书籍和网络.如有什么不对的,请各位批评指正.以下的类有的并不完全,只列出重要的方法. 如要转载,请注上作者以及出处. 一.源码阅读环境 需要安装jdk1.7.0版本及其以上版本, ...

  9. 使用mysqlfrm恢复frm表结构,获得建表语句

    1.mysqlfrm 是一个恢复性质的工具,用来读取.frm文件并从该文件中找到表定义数据生成CREATE语句. 下载链接:https://downloads.mysql.com/archives/u ...

  10. Android Handler消息机制源码解析

    好记性不如烂笔头,今天来分析一下Handler的源码实现 Handler机制是Android系统的基础,是多线程之间切换的基础.下面我们分析一下Handler的源码实现. Handler消息机制有4个 ...