单例:只能实例化一个对象,使用场景比如打印机。

最推荐的是采用饿汉式;双重校验锁用到了大量的语法,不能保证这些语法在所用场合一定没问题,所以不是很推荐;总之简单的才是最好的,就饿汉式!!!

C++ 创建变量可以通过 类名 对象名,但是 JAVA 不行

C++ new 出来的对象需要手动回收,但是 JAVA 可以自动回收

C++ new 出来的对象需要用指针接收,但是 JAVA 对象变量就可以接收,或者说 JAVA 的对象变量就是指针

1、(懒汉,线程安全 ------ 不推荐)

public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

说明:在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的

2、(饿汉 ------ 推荐)

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

说明:instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载。所以,会出现在使用对象前就创建好,占用了资源

3、(静态内部类 ------ 推荐)

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

说明:第三种和第二种的区别在于,第三种类被装载也不会实例化对象,一定要调用 getInstance() 才会实例化,而且只实例化一次。

4、(双重校验锁 ------ 一般推荐<理解麻烦>)

public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton (){}
public static Singleton getSingleton() {
if (uniqueInstance == null) { // #1
synchronized (Singleton.class) { // #2
if (uniqueInstance == null) { // #3
uniqueInstance = new Singleton(); // #4
}
}
}
return singleton;
}
}

说明:和第一种方式比,这种方式只会第一次调用创建对象时使用同步锁

对象singleton 用 volatile 修饰,原因举例如下:

1. thread2进入#1, 假设这时子线程的uniqueInstance为空(java内存模型会从主线程拷贝一份uniqueInstance=null到子线程thread2),然后thread2让出CPU资源给thread3
2. thread3进入#1, 这时子线程的uniqueInstance还是为空(java内存模型会从主线程拷贝一份uniqueInstance=null到子线程thread3),然后thread3让出CPU资源给thread2
3. thread2会依次执行#2,#3,#4,最终在thread2里面实例化了uniqueInstance(由于是volatile修饰的变量,会马上同步到主线程的变量去),thread2执行完毕让出CPU资源给thread3
4. thread3接着#1跑下去,跑到#3的时候,会又一次从主线程拷贝一份uniqueInstance!=null回来,所以thread3就不会实例化对象

  上面解释的是 volatile 保证变量可见性的体现,使每个线程得到的变量来源都是唯一的;同时 volatile 还能保证变量的有序性," new Singleton "的执行其实是分三步走,第一:分配内存,第二:执行构造函数,第三:赋值,准确的说应该是引用;如果没有 volatile 修饰,在保证结果的情况下(单线程,或者是本线程中)编译器可能会打乱执行顺序,如果有另外一个线程在执行 #1 判断变量不为nll,但是此变量没有执行构造函数,获取的对象是不完整的,程序就可能发生错误。java的volatile顺序性方面比C++强,能保证此顺序执行。

  volatile 防止编译器把两个 if 优化成一个 if 。

疑问:

1、如果赋值不是原子操作,会不会出现,没完全赋值完成就被另外一个线程使用了

单例 ------ JAVA实现的更多相关文章

  1. 单例 (JAVA)

    java中单例模式是一种常见的设计模式,以下是它的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例 第一种(懒汉,线程不安全):  1 publ ...

  2. javaWeb项目中到底什么是单例,多例

    你用杯子喝可乐,喝完了不刷,继续去倒果汁喝,就是单例.你用杯子喝可乐,直接扔了杯子,换个杯子去倒果汁喝,就是多例. 数据库连接池就是单例模式,有且仅有一个连接池管理者,管理多个连接池对象. 1. 什么 ...

  3. java 单例

    Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例.饿汉式单例. 饿汉式和懒汉式区别 从名字上来说,饿汉和懒汉, 饿汉就是类一旦加载,就把单例初始化完成,保证 ...

  4. Java设计模式之单例

    一.Java中的单例: 特点: ① 单例类只有一个实例 ② 单例类必须自己创建自己唯一实例 ③ 单例类必须给所有其他对象提供这一实例 二.两种模式: ①懒汉式单例<线程不安全> 在类加载时 ...

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

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

  6. Java 多线程之单例设计模式

    转载:https://segmentfault.com/a/1190000007504892 概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例.饿汉 ...

  7. java单例类/

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

  8. java单例-积木系列

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

  9. 如何防止JAVA反射对单例类的攻击?

    在我的上篇随笔中,我们知道了创建单例类有以下几种方式: (1).饿汉式; (2).懒汉式(.加同步锁的懒汉式.加双重校验锁的懒汉式.防止指令重排优化的懒汉式); (3).登记式单例模式; (4).静态 ...

随机推荐

  1. C++ ifndef /define/ endif 作用和用法

    ifndef/define/endif”主要目的是防止头文件的重复包含和编译 比如你有两个C文件,这两个C文件都include了同一个头文件.而编译时,这两个C文件要一同编译成一个可运行文件,于是问题 ...

  2. Paper Reading - Learning to Evaluate Image Captioning ( CVPR 2018 ) ★

    Link of the Paper: https://arxiv.org/abs/1806.06422 Innovations: The authors propose a novel learnin ...

  3. LeetCode 142——环形链表 II

    1. 题目 2. 解答 2.1 方法 1 定义快慢两个指针,慢指针每次前进一步,快指针每次前进两步,若链表有环,则快慢指针一定会相遇. 当快慢指针相遇时,我们让慢指针指向头节点,快指针不变,然后每次快 ...

  4. Icingaweb2监控oracle数据库的安装配置流程

    Icinga2安装配置check_oracle_health流程 1.安装 由于check_oracle_health是使用perl语言编写的,因此在安装该插件之前,首先要安装oracle的客户端实例 ...

  5. return阻止js继续向下执行

    终止JS运行有如下几种可能: 终止函数的运行的方式有两种 在函数中使用return,则当遇到return时,函数终止执行,控制权继续向下运行 在函数中使用try-catch异常处理,需要结束时,使用t ...

  6. ACM 第十九天

    积性函数 积性函数线性筛,筛素数,u(n),欧拉函数: vis[]=vis[]=,mu[]=,phi[]=; ;i<=N;++i){ ,phi[i]=i-,prime[++cnt]=i; ,k= ...

  7. Debian实验机 常用命令

    1.开启中文输入法 fcitx 2. 开启无线连接 wicd 3. 远程连接 ssh root@XXX.XXX.XXX.XXX 4. 启动Ulipad ~/ulipad-master# python ...

  8. TCP系列08—连接管理—7、TCP 常见选项(option)

    一.TCP选项概述 在前面介绍TCP头的时候,我们说过tcp基本头下面可以带有tcp选项,其中有些选项只能在连接过程中随着SYN包发送,有些可以延后.下表汇总了一些tcp选项 其中我标记为红色的部分是 ...

  9. JSP传递数组给JS的方法

    由于JSP页面的数组无法直接传到JS.所以采用以下方法来获取数组. <% String[] title = { "姓名 ", "学号 ", "性 ...

  10. lol人物模型提取(八)

      今天顺风终于把包裹送到了北航新主楼自提柜,怀着激动喜悦的心情,我小心翼翼地将其取回.   到了晚上,是时候解开佐伊的封印了!   开了个小口,发现里面包得还挺严实的.   去掉了纸盒,里面还有一层 ...