单例 ------ JAVA实现
单例:只能实例化一个对象,使用场景比如打印机。
最推荐的是采用饿汉式;双重校验锁用到了大量的语法,不能保证这些语法在所用场合一定没问题,所以不是很推荐;总之简单的才是最好的,就饿汉式!!!
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实现的更多相关文章
- 单例 (JAVA)
java中单例模式是一种常见的设计模式,以下是它的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例 第一种(懒汉,线程不安全): 1 publ ...
- javaWeb项目中到底什么是单例,多例
你用杯子喝可乐,喝完了不刷,继续去倒果汁喝,就是单例.你用杯子喝可乐,直接扔了杯子,换个杯子去倒果汁喝,就是多例. 数据库连接池就是单例模式,有且仅有一个连接池管理者,管理多个连接池对象. 1. 什么 ...
- java 单例
Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例.饿汉式单例. 饿汉式和懒汉式区别 从名字上来说,饿汉和懒汉, 饿汉就是类一旦加载,就把单例初始化完成,保证 ...
- Java设计模式之单例
一.Java中的单例: 特点: ① 单例类只有一个实例 ② 单例类必须自己创建自己唯一实例 ③ 单例类必须给所有其他对象提供这一实例 二.两种模式: ①懒汉式单例<线程不安全> 在类加载时 ...
- java单例的几种实现方法
java单例的几种实现方法: 方式1: public class Something { private Something() {} private static class LazyHolder ...
- Java 多线程之单例设计模式
转载:https://segmentfault.com/a/1190000007504892 概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例.饿汉 ...
- java单例类/
java单例类 一个类只能创建一个实例,那么这个类就是一个单例类 可以重写toString方法 输出想要输出的内容 可以重写equcal来比较想要比较的内容是否相等 对于final修饰的成员变量 一 ...
- java单例-积木系列
一步步知识点归纳吧,把以前似懂非懂,了解表面,知道点不知道面的知识归一下档. 懒汉式单例: 私有化构造函数,阻止外界实例话对象,调用getInstance静态方法,判断是否已经实例化. 为什么是懒 ...
- 如何防止JAVA反射对单例类的攻击?
在我的上篇随笔中,我们知道了创建单例类有以下几种方式: (1).饿汉式; (2).懒汉式(.加同步锁的懒汉式.加双重校验锁的懒汉式.防止指令重排优化的懒汉式); (3).登记式单例模式; (4).静态 ...
随机推荐
- 拥抱移动端,jQueryui触控设备兼容插件
http://touchpunch.furf.com/ ps:要FQ. jQuery UI Touch Punch Touch Event Support for jQuery UI Tested o ...
- Vue-cli 工具 / 通过 Vue-cli 工具重构 todoList
本博文归纳在 Vue 学习过程中, Vue-cli 工具的使用说明.除此之外还通过 Vue-cli 工具将之前 Vuejs 基本语法当中实现的 todoList 进行重构. 安装 npm instal ...
- linux 命令行基础
命令行基础 一些名词 「图形界面」 「命令行」 「终端」 「shell」 「bash」 安装使用 Windws: 安装git, 打开 gitbash Linux 打开终端 Mac 打开终端 基本命令 ...
- HTML/JSP中一些单书名号标签的用途<%-- --%><!-- --><%@ %><%! %><% %><%= %>
注释 <%-- --%>是(JSP)隐式注释,不会在页面显示的注释 <!-- -->是(Html)显示注释,会在JSP页面显示 关于注释还有单行隐式注释//和多行隐式注释/* ...
- Java中的线程同步
Java 中的线程同步问题: 1. 线程同步: 对于访问同一份资源的多个线程之间, 来进行协调的这个东西. 2. 同步方法: 当某个对象调用了同步方法时, 该对象上的其它同步方法必须等待该同步方法执行 ...
- iOS开发实现UIView随着子控件的高度的变化而变化
例子 其实看完上面的叙述,你会思考,到底什么情况下,一个UIView需要只设置坐标不设置大小呢?其实这种场景相当普遍.比如,我们常常会碰到,一个View中有两个Label,两个Label的高度均和内容 ...
- bwapp之xss(blog)
存储型XSS,持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行.这种XSS比较危险,容易造 ...
- ubuntu搭建eclipse+svn
最近工作中要求使用ubuntu系统进行开发,小编第一次使用,将搭建环境的过程中一点点经验分享给大家.ubuntu的使用跟linux差不太多,大多数命令还是一样的.不过界面要好看很多,O(∩_∩)O哈哈 ...
- dwarf是如何处理栈帧的?
dwarf是如何处理栈帧的? DW_AT_frame_base 表明函数栈帧的起始点 95 < 1><0x000000ca> DW_TAG_subprogram 96 ...
- [剑指Offer] 57.二叉树的下一个结点
题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. /* struct TreeLinkNode { in ...