双重检验锁实现方式

public class Singleton {
//定义一个私有的空构造方法,防止直接用new实例化
private Singleton() {} private static volatile Singleton singleton = null; public static Singleton getInstance() {
if(singleton == null) {
synchronized(Singleton.class) {
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

双重校验锁,从代码的中可以看出,在同步代码块外多了一层instance为空的判断,由于单例对象只需要创建一次,如果后面再次调用getInstance()只需要直接返回单例对象即可,因此,在大部分情况下,调用getInstance()都不会执行到同步代码块,从而提高的程序性能。但是还需要考虑一种情况,假如两个线程A、B,线程A执行了if(instance == null)语句,它会任务单例对象没有创建,此时线程切到B也执行了同样的语句,B也认为单例对象没有创建,然后两个线程一次执行同步代码块,并分别创建了一个单例对象,所以为了解决这个问题,还需要在同步代码块中增加if(instance == null)的语句判断,避免重复创建的问题。

可以发现instance变量使用了volatile修饰,这样做的目的在于禁止指令重排序优化,所谓指令重排序优化是指在不改变原语义的前提下,通过调整指令的执行顺序让程序运行的更快,JVM中并没有规定编译器优化的相关内容,也就是说JVM可以自由的镜像指令重排序优化,这样会导致Singleton和将对象赋值给instance字段的顺序是不确定的。在摸个线程创建单例对象时,在构造方法被调用之前,就为该对象分配了内存空间将对象的字段设置为默认值。此时就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化,若紧接着另一个线程来调用getInsatance,取到的就是状态不正确的对象,程序就会出错。volatile的一个语义是禁止指令重排序优化,也就是保证了instance遍历被赋值的时候对象已经是初始化过的,从而避免上面说的问题。

静态内部类实现方式

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

这种方式同样利用了类加载机制来保证只创建一个instance实例。它与饿汉模式一样,也是利用了类加载机制,因此不存在多线程并发的问题。不一样的是,它是在内部类里面去创建对象实例。这样的话,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。也就是说这种方式可以同时保证延迟加载和线程安全。

Java单例实现及分析的更多相关文章

  1. java单例的几种实现方法

    java单例的几种实现方法: 方式1: public class Something { private Something() {} private static class LazyHolder ...

  2. java单例类/

    java单例类  一个类只能创建一个实例,那么这个类就是一个单例类 可以重写toString方法 输出想要输出的内容 可以重写equcal来比较想要比较的内容是否相等 对于final修饰的成员变量 一 ...

  3. java单例-积木系列

    一步步知识点归纳吧,把以前似懂非懂,了解表面,知道点不知道面的知识归一下档.   懒汉式单例: 私有化构造函数,阻止外界实例话对象,调用getInstance静态方法,判断是否已经实例化. 为什么是懒 ...

  4. Java单例类的简单实现

    对于java新手来说,单例类给我的印象挺深,之前一道web后台笔试题就是写单例类.*.*可惜当时不了解. 在大部分时候,我们将类的构造器定义成public访问权限,允许任何类自由创建该类的对象.但在某 ...

  5. 【Java学习笔记之三十】详解Java单例(Singleton)模式

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

  6. 转:java单例设计模式

    本文转自:http://www.cnblogs.com/yinxiaoqiexuxing/p/5605338.html 单例设计模式 Singleton是一种创建型模式,指某个类采用Singleton ...

  7. 熟悉的味道——从Java单例写到C++单例

    设计模式中,单例模式是常见的一种.单例模式需要满足以下两个条件: 保证一个类只能创建一个示例: 提供对该实例的全局访问点. 关于单例最经典的问题就是DCL(Double-Checked Lock),今 ...

  8. java单例五种实现模式梳理

    java单例五种实现模式 饿汉式(线程安全,调用效率高,但是不能延时加载) 一上来就把单例对象创建出来了,要用的时候直接返回即可,这种可以说是单例模式中最简单的一种实现方式.但是问题也比较明显.单例在 ...

  9. JAVA单例实现方式(常用)

    JAVA单例实现方式(常用) public class Singleton { // Q1:为什么要使用volatile关键字? private volatile static Singleton u ...

随机推荐

  1. ForkJoinPool

    fork():开启一个新线程(或是重用线程池内的空闲线程),将任务交给该线程处理. join():等待该任务的处理线程处理完毕,获得返回值. ForkJoinPool 的每个工作线程都维护着一个工作队 ...

  2. dynamic的使用

    一.在没有dynamic之前,我们想要获取返回object对象里的属性的值时,使用反射的方法来获取该对象的属性值. class Program { static void Main(string[] ...

  3. drf 多表

    https://www.django-rest-framework.org/  官方站 https://www.django-rest-framework.org/tutorial/quickstar ...

  4. datagridview 添加数据库数据

    private void btnadd_Click(object sender, EventArgs e) { string str = @"Data Source=(localdb)\MS ...

  5. Sql Server语句大全

    T-SQL语句大全 --跳转到SQL myDemo USE [SQL myDemo] go --声明变量id declare @id int --为变量赋值:直接赋值 --将cid为3的cname值赋 ...

  6. deepin Gtk-WARNING **: 无法在模块路径中找到主题引擎:“adwaita”

    虽然没影响使用,但是看着有点不爽. 执行 sudo apt-get install gnome-themes-standard 就可以了.

  7. 防止sql注入(简单)

    (1)mysql_real_escape_string -- 转义 SQL 语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集 使用方法如下: $sql = "select count ...

  8. sdoi2018旧试题 证明

  9. pandas替换一列中的汉字为数字

    表格的一列“总金额”应该全部为数字,但其中少数项出现汉字,应该将汉字替换为数字,才能进行后面的计算. 先定义一个函数: def is_number(s): try: float(s) return T ...

  10. IDEA 创建 web项目

    创建web步骤: 1.创建一个project File -> New Project -> 选择Java,Project SDK为1.7,勾选Web Application(创建web.x ...