Java 多线程(四)—— 单例模式
这篇博客介绍线程安全的应用——单例模式。
单例模式
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
双重校验锁
实例:
/**
* @author: ChenHao
* 关于懒汉式的线程安全问题,使用同步机制
* 对于一般的方法内,使用同步方法块,可以考虑使用this
* 对于静态方法而言,使用当前类充当锁。
*/
public class TestSingleton {
public static void main(String[] args) {
System.out.println(MySingle.getInstance());
System.out.println(MySingle.getInstance());
}
} class MySingle{
//声明一个私有的静态变量,第一次调用才初始化,避免内存浪费。
private volatile static MySingle instance=null;
//让构造器为private私有化,避免外部直接创建对象
private MySingle(){}
public static MySingle getInstance(){
if(null ==instance){//提高效率:如果已经存在对象,则不进行锁等待,直接返回对象,只有当对象为空才会进入锁等待,这里可以在第一个进入锁创建对象后,sleep10秒来放大效果
//这里有五个线程等待
synchronized(MySingle.class){
//第一次:当一个线程进来后,其他线程都在锁外面
//第一个线程创建对象后,释放锁,其他线程得到锁后,如果instance不为null,则不需要创建
if(null ==instance){
instance =new MySingle();
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
return instance;
}
}
代码分析:多个线程同时创建MySingle类的实例,比如现在有6个线程,第一次同时调用getInstance()静态方法,
线程A获取了锁,其他5个线程都在synchronized(MySingle.class)外面等待,第一个线程创建对象后,释放锁,其他线程得到锁后,如果instance不为null,则不需要创建;
第一个if(null ==instance)作用是提高效率:如果已经存在对象,则不进行锁等待,直接返回对象,只有当对象为空才会进入锁等待,这里可以在第一个进入锁创建对象后,sleep10秒来放大效果,此时已经创建了instance ,但是还没有释放锁,所以新来的线程不需要再等待锁,直接使用已经创建好的instance;
第二个if(null ==instance)判断instance是否已经存在,如果第一个线程已经创建instance,并释放锁,接下来的线程进入后则不需要再创建;
运行结果:输出相同的对象实例

饿汉
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
CAS(AtomicReference)实现单例模式
public class Singleton {
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();
private Singleton() {}
public static Singleton getInstance() {
for (;;) {
Singleton singleton = INSTANCE.get();
if (null != singleton) {
return singleton;
}
singleton = new Singleton();
if (INSTANCE.compareAndSet(null, singleton)) {
return singleton;
}
}
}
}
用CAS的好处在于不需要使用传统的锁机制来保证线程安全,CAS是一种基于忙等待的算法,依赖底层硬件的实现,相对于锁它没有线程切换和阻塞的额外消耗,可以支持较大的并行度。
CAS的一个重要缺点在于如果忙等待一直执行不成功(一直在死循环中),会对CPU造成较大的执行开销。而且,这种写法如果有多个线程同时执行singleton = new Singleton();也会比较浪费堆内存。
Java 多线程(四)—— 单例模式的更多相关文章
- java 多线程四
java 多线程一 java 多线程二 java 多线程三 java 多线程四 一个生产者,消费者的例子: import java.util.Stack; /** * Created by root ...
- java多线程(四)-自定义线程池
当我们使用 线程池的时候,可以使用 newCachedThreadPool()或者 newFixedThreadPool(int)等方法,其实我们深入到这些方法里面,就可以看到它们的是实现方式是这样的 ...
- java多线程与单例模式(Singleton)不得不说的故事
转发自:http://blog.csdn.net/ligang7560/article/details/50890282 单例模式的多种实现方式 我们都知道单例模式有几种常用的写法: - 饿汉模式 - ...
- Java多线程(四) 线程池
一个优秀的软件不会随意的创建.销毁线程,因为创建和销毁线程需要耗费大量的CPU时间以及需要和内存做出大量的交互.因此JDK5提出了使用线程池,让程序员把更多的精力放在业务逻辑上面,弱化对线程的开闭管理 ...
- java多线程四种实现模板
假设一个项目拥有三块独立代码块,需要执行,什么时候用多线程? 这些代码块某些时候需要同时运行,彼此独立,那么需要用到多线程操作更快... 这里把模板放在这里,需要用的时候寻找合适的来选用. 总体分为两 ...
- Java多线程(四) —— 线程并发库之Atomic
一.从原子操作开始 从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作,因此首先从这里开始). 很多情况下 ...
- java多线程环境单例模式实现详解
Abstract 在开发中,如果某个实例的创建需要消耗很多系统资源,那么我们通常会使用惰性加载机制,也就是说只有当使用到这个实例的时候才会创建这个实例,这个好处在单例模式中得到了广泛应用.这个机制在s ...
- java 多线程,单例模式类(创建对象)最优写法
单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ...
- Java多线程之单例模式(线程安全)
package org.study2.javabase.ThreadsDemo.sync; /** * @Auther:GongXingRui * @Date:2018/9/20 * @Descrip ...
- java多线程(四)之同步机制
1.同步的前提 多个线程 多个线程使用的是同一个锁 2.同步的好处 同步的出现解决了多线程的安全问题 3.同步的弊端 当线程较多时, 因为每个线程都会去判断同步上的锁, 这样是很耗费资源的, 会降低程 ...
随机推荐
- 20175305张天钰《java程序设计》第七周学习总结
<java程序设计>第七周学习总结 第八章 常用实用类 1.String类 1.String类不可以有子类. 2.用户无法输出String对象的引用,输出的是字符序列 3.构造方法:Str ...
- ECMAScript 6 之 let 和 const 命令
1.let基本用法 1.1.声明变量 let声明的变量只在它所在的代码块有效. 1.2.不存在变量提升 var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined: let命令 ...
- Hive的DDL操作
DDL:data definittion language 数据定义语言 主要是定义或改变表的结构.数据类型.表之间的链接和约束等初始化操作 DML:data manipulation languag ...
- Y1吐槽001 怎么做产品
做一个产品,这个产品是做给用户用的还是做给领导看的完全是两个不同的出发点..做给领导看有好处,毕竟领导有知道进展的权利和指导方向的作用,还有一个好处就是表现得好. 忽略了使用者的感受是非常致命的,标模 ...
- 创建一个git仓库
1.git init 使用git init命令初始化一个git仓库,git仓库会生成一个.git目录 git init 1.使用指定的目录作为我们的git仓库 git init newrepo 2.初 ...
- 201771010126 王燕《面向对象程序设计(Java)》第十三周学习总结
实验十三 图形界面事件处理技术 实验时间 2018-11-22 1.实验目的与要求 (1) 掌握事件处理的基本原理,理解其用途: 事件源 (eventevent eventeventsource s ...
- python中的单向循环链表实现
引子 所谓单向循环链表,不过是在单向链表的基础上,如响尾蛇般将其首尾相连,也因此有诸多类似之处与务必留心之点.尤其是可能涉及到头尾节点的操作,不可疏忽. 对于诸多操所必须的遍历,这时的条件是什么?又应 ...
- js的一些function
/** * * 根据秒数返回 一个日期范围 * timerFilter(10) */ function timerFilter(n) { let days = 31; // 一月多少天 const o ...
- laravel之知识点
- 删除 id 列表 存进数据库
当图片写的传id的时候 用着方法存进数据库