这篇博客介绍线程安全的应用——单例模式。

单例模式

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。

双重校验锁

实例:

/**
* @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 多线程(四)—— 单例模式的更多相关文章

  1. java 多线程四

    java 多线程一 java 多线程二 java 多线程三 java 多线程四 一个生产者,消费者的例子: import java.util.Stack; /** * Created by root ...

  2. java多线程(四)-自定义线程池

    当我们使用 线程池的时候,可以使用 newCachedThreadPool()或者 newFixedThreadPool(int)等方法,其实我们深入到这些方法里面,就可以看到它们的是实现方式是这样的 ...

  3. java多线程与单例模式(Singleton)不得不说的故事

    转发自:http://blog.csdn.net/ligang7560/article/details/50890282 单例模式的多种实现方式 我们都知道单例模式有几种常用的写法: - 饿汉模式 - ...

  4. Java多线程(四) 线程池

    一个优秀的软件不会随意的创建.销毁线程,因为创建和销毁线程需要耗费大量的CPU时间以及需要和内存做出大量的交互.因此JDK5提出了使用线程池,让程序员把更多的精力放在业务逻辑上面,弱化对线程的开闭管理 ...

  5. java多线程四种实现模板

    假设一个项目拥有三块独立代码块,需要执行,什么时候用多线程? 这些代码块某些时候需要同时运行,彼此独立,那么需要用到多线程操作更快... 这里把模板放在这里,需要用的时候寻找合适的来选用. 总体分为两 ...

  6. Java多线程(四) —— 线程并发库之Atomic

    一.从原子操作开始 从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作,因此首先从这里开始). 很多情况下 ...

  7. java多线程环境单例模式实现详解

    Abstract 在开发中,如果某个实例的创建需要消耗很多系统资源,那么我们通常会使用惰性加载机制,也就是说只有当使用到这个实例的时候才会创建这个实例,这个好处在单例模式中得到了广泛应用.这个机制在s ...

  8. java 多线程,单例模式类(创建对象)最优写法

    单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ...

  9. Java多线程之单例模式(线程安全)

    package org.study2.javabase.ThreadsDemo.sync; /** * @Auther:GongXingRui * @Date:2018/9/20 * @Descrip ...

  10. java多线程(四)之同步机制

    1.同步的前提 多个线程 多个线程使用的是同一个锁 2.同步的好处 同步的出现解决了多线程的安全问题 3.同步的弊端 当线程较多时, 因为每个线程都会去判断同步上的锁, 这样是很耗费资源的, 会降低程 ...

随机推荐

  1. 将source类中的属性值赋给target类中对应的属性

    /** * 对象的属性值拷贝 * <p> * 将source对象中的属性值赋值到target对象中的属性,属性名一样,类型一样 * <p> * example: * <p ...

  2. jquery.string.js

    /** * jquery.string - Prototype string functions for jQuery * version: 1.1.0 * (c) 2008-2011 David E ...

  3. PLS:利用PLS(两个主成分的贡献率就可达100%)提高测试集辛烷值含量预测准确度并《测试集辛烷值含量预测结果对比》—Jason niu

    load spectra; temp = randperm(size(NIR, 1)); P_train = NIR(temp(1:50),:); T_train = octane(temp(1:50 ...

  4. 微软官网tools

    DHCP/AD域插件: 远程管理工具(含DHCP/AD域) 安装网址: https://www.microsoft.com/zh-cn/download/details.aspx?id=7887 程序 ...

  5. dotnetcore Http服务器研究(一)

    自从dotnet core 诞生以来,发展非常强势.我们总有些需要写一个独立的http服务器的需求,我想是时候忘记httplistener 了. dotnet framework 时代建一个小的htt ...

  6. patch 请求时,关于id的报错问题

    在更新操作时,先显示要更新的数据内容,再修改 在发送patch请求时出现 After applying the update to the document {_id: ObjectId('55be3 ...

  7. BZOJ3497 : Pa2009 Circular Game

    令先手为$A$,后手为$B$,将相邻同色棋子合并成块,首先特判一些情况: 如果所有格子都是满的,那么显然$A$必败. 否则如果所有块都只有一个棋子,那么显然平局. 枚举$A$的第一步操作,如果可以使得 ...

  8. input框中修改placeholder的样式

    有时间input标签的placeholder属性会出现问题,下面是修改placeholder的样式demo input::-webkit-input-placeholder{ color:red; f ...

  9. vue 源码学习三 vue中如何生成虚拟DOM

    vm._render 生成虚拟dom 我们知道在挂载过程中, $mount 会调用 vm._update和vm._render 方法,vm._updata是负责把VNode渲染成真正的DOM,vm._ ...

  10. md5 加密文件

    import hashlibimport os def get_md5(file_path): md5 = None if os.path.isfile(file_path): f = open(fi ...