原子

AtomicXXX系列类使用分析

巧了我就是萌 提交于 2020-01-08 10:31:20
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 在 java.util.concurrent.atomic 中,普通的原子类型有以下四种: AtomicBoolean:提供对基本数据类型boolean的原子性更新操作。 AtomicInteger:提供对基本数据类型int的原子性更新操作。 AtomicLong:提供对基本数据类型long的原子性更新操作。 AtomicReference :这是一个泛型类,提供对引用类型的原子性更新操作。 数组相关的操作类有: AtomicLongArray:提供对int[]数组元素的原子性更新操作。 AtomicIntegerArray:提供对long[]数组元素的原子性更新操作。 AtomicReferenceArray:提供对引用类型[]数组元素的原子性更新操作。 由于上面的原子操作类的实现原理差不多,我们这边就选择 AtomicInteger 来分析。 代码分析 构造函数 public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID =

Atomic系列类整体介绍

╄→尐↘猪︶ㄣ 提交于 2020-01-07 12:26:20
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 本文是转载文章,原文请见 此博客 ,文章主要对 java.util.concurrent.atomic 开发包下的类进行整体概述与类别划分。 版本说明 在JDK1.5版本之前,多行代码的原子性主要通过synchronized关键字进行保证。 在JDK1.5版本,Java提供了原子类型专门确保变量操作的原子性。 开发包整体说明 原子类型位于java.util.concurrent.atomic包下,其主要类如下: 其类图关系如下: 原子类型划分 为了方面对这些类逐级掌握,我将这些原子类型分为以下几类: 普通原子类型:提供对boolean、int、long和对象的原子性操作。 AtomicBoolean AtomicInteger AtomicLong AtomicReference 原子类型数组:提供对数组元素的原子性操作。 AtomicLongArray AtomicIntegerArray AtomicReferenceArray 原子类型字段更新器:提供对指定对象的指定字段进行原子性操作。 AtomicLongFieldUpdater AtomicIntegerFieldUpdater

并发编程的基石——CAS机制

爷,独闯天下 提交于 2020-01-07 11:29:35
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 Java中提供了很多原子操作类来保证共享变量操作的原子性。这些原子操作的底层原理都是使用了CAS机制。在使用一门技术之前,了解这个技术的底层原理是非常重要的,所以本篇博客就先来讲讲什么是CAS机制,CAS机制存在的一些问题以及在Java中怎么使用CAS机制。 其实Java并发框架的基石一共有两块,一块是本文介绍的CAS,另一块就是AQS,后续也会写博客介绍。 什么是CAS机制 CAS机制是一种数据更新的方式。在具体讲什么是CAS机制之前,我们先来聊下在多线程环境下,对共享变量进行数据更新的两种模式:悲观锁模式和乐观锁模式。 悲观锁更新的方式认为:在更新数据的时候大概率会有其他线程去争夺共享资源,所以悲观锁的做法是:第一个获取资源的线程会将资源锁定起来,其他没争夺到资源的线程只能进入阻塞队列,等第一个获取资源的线程释放锁之后,这些线程才能有机会重新争夺资源。synchronized就是java中悲观锁的典型实现,synchronized使用起来非常简单方便,但是会使没争抢到资源的线程进入阻塞状态,线程在阻塞状态和Runnable状态之间切换效率较低(比较慢)。比如你的更新操作其实是非常快的

Java并发编程---原子操作CAS

≯℡__Kan透↙ 提交于 2020-01-07 01:25:33
实现并发操作的方法有两种:一种是使用锁(Synchronized和Lock),另外一种是使用原子操作(CAS) Synchronized基于阻塞的锁机制可能会带来的问题: a. 被阻塞的线程优先级很高 b.拿到锁的线程一直不释放锁怎么办? c.大量的竞争消耗cpu,同时带来死锁或者其他安全问题 基于上述问题,提出了CAS原子操作 a.CAS原理:利用现代处理器都支持的CAS指令,循环这个指令,直到成功为止 b.CAS(Compare And Swap) : 指令级别上保证这是一个原子操作 c.与CAS相关的三个运算符:一个内存地址V,一个期望值A,一个新值B 基本思路:如果地址V上的值和期望的值A相等,就给地址V赋新值B,如果不是,不做任何操作。 (在(死循环)循环中不断进行CAS操作) d.CAS也会带来一定的问题: 1)ABA问题(A–>B–>A):当第一次取内存地址V时,取到了A的值,可当它要执行CAS操作之前,已经有一个线程对A的值改为B后,再 改为A,这时候的值虽然一样,不过内容已经有过更改。(举例:在现实生活中,你放在座子上的以一杯水被同事喝完,又重新倒满一杯放在那里。很明显,它虽然还是那杯满着的水,可性质上却完全不一样了。) 解决方法:可以通过版本号解决 A1—>B2---->A3 (类似于乐观锁,大多是基于数据版本( Version )记录机制实现。) 2)开销问题

Java 理论与实践: 正确使用 Volatile 变量--转

耗尽温柔 提交于 2020-01-05 04:07:19
原文地址:http://www.ibm.com/developerworks/cn/java/j-jtp06197.html Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized ”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。本文介绍了几种有效使用 volatile 变量的模式,并强调了几种不适合使用 volatile 变量的情形。 锁提供了两种主要特性: 互斥(mutual exclusion) 和 可见性(visibility) 。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。 Volatile 变量 Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例

原子操作类AtomicInteger

为君一笑 提交于 2020-01-04 03:16:15
目录 为什么需要原子操作类 如果使用volatile修饰变量呢 使用AtomicInteger CAS指令 incrementAndGet()方法 JUC包原子类的类型及方法 为什么需要原子操作类 原子操作,是指一个操作是不可分割,不可中断的; 在java中的运算操作,例如自增或自减,若没有进行额外的同步操作,在多线程环境下操作就是线程不安全的;(n++解析为n=n+1,明显这个操作不具备原子性,多线程并发共享这个变量时必然会出现问题) 如果使用volatile修饰变量呢 volatile特性 可见性,保证被修饰的变量在线程间可见,对变量的所有写操作都能立即反应到其他线程中;即volatile修饰的变量在各个线程中是一致的; 只是保证了可见性,在并发情况下并不能保证线程安全(n++不具备原子性) 使用AtomicInteger incrementAndGet()方法具备原子性 同步 ,多线程并发访问共享数据时,保证共享数据在同一时刻只被一个线程或一些使用; 阻塞同步和非阻塞同步都是实现线程安全的两个保障手段;非阻塞同步主要解决了阻塞同步中线程阻塞和唤醒带来的性能问题; 非阻塞同步 :在并发环境下,某个线程对共享变量先进行操作;如果没有其他线程争用共享数据那操作就成功;如果存在数据争用冲突,就采取补偿措施,比如重试机制,直到成功为止;因为这中乐观的并发策略不需要把线程挂起

CAS都不了解,你还怎么看J.U.C

一笑奈何 提交于 2020-01-03 22:37:40
前言 说到 CAS (CompareAndSwap),不得不先说一说 悲观锁 和 乐观锁 ,因为CAS是乐观锁思想的一种实现。 悲观锁 :总是很悲观的认为,每次拿数据都会有其他线程并发执行,所以每次都会进行加锁,用完之后释放锁,其他的线程才能拿到锁,进而拿到资源进行操作。java中的synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。 乐观锁 :总是很乐观认为,自己拿到数据操作的时候,没有其他线程来并发操作,等自己操作结束要更新数据时,判断自己对数据操作的期间有没有其他线程进行操作,如果有,则进行重试,直到操作变更成功。乐观锁常使用CAS和版本号机制来实现。java中 java.util.atomic 包下的原子类都是基于CAS实现的。 一、什么是CAS CAS指 CompareAndSwap ,顾名思义, 先比较后交换 。比较什么?交换什么呢? CAS中有三个变量:内存地址V,期待值A, 更新值B。 当且仅当内存地址V对应的值与期待值A时相等时,将内存地址V对应的值更换为B。 二、atomic包 有了悲观锁,乐观锁的知识,让我们走进java.util.atomic包,看一看java中CAS的实现。 这就是 java.util.atomic 包下的类,我们着重看AtomicInteger源码(其他的都是一样的思想实现的) 然后思考CAS有什么弊端

DOCK6学习(2)

假装没事ソ 提交于 2020-01-02 16:27:37
DOCK6学习II DOCK6 的工作流程 DOCK6工作流程概论 DOCK6基本理念 DOCK6相关概念 (A)Sphere Centers (B)化学匹配 (C) Critical Points (D)Bump Filter DOCK6 的工作流程 本文是咸鱼博主根据dock6.9的手册总结出,只是针对小分子-蛋白相互作用和Amber Score。感觉也不会有人看,但又怕后面没人接暂时写下来的了233。(实际上就是个搬运翻译而已和自己的操作而已啦。) DOCK6工作流程概论 DOCK6.9的工作流程如图。首先是根据`受体(Receptor)和配体(ligand)的几何坐标来进行准备,而后进行docking。受体的准备有三个流程: Sphgen , Grid 和 DOCK 。 Sphgen 流程识别相应位点,并生成可填满位点的球心。 Grid 流程则生成记分网格。在程序 DOCK 中, DOCK 将球体(由 Sphgen 生成)与配体原子相匹配,并使用记分网格(来自 Grid )来评估配体的取向。程序对接还可以最小化基于能量的分数。 DOCK6基本理念 针对docking,DOCK的处理方式是: (1)确定配体相对蛋白的方位, (2)确定给配体方位的打分方式. DOCK这个方式中的两种处理方式都可以进行替换。替换成自己需要的方式来进行 确定配体的方位的步骤: (1

Java中的13个原子操作类

空扰寡人 提交于 2020-01-01 15:34:06
目录 原子更新基本类型类 原子更新数组 原子更新引用类型 原子更新字段类 当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变 量i=1, A线程更新i+1, B线程也更新i+ 1, 经过两个线程橾作之后可能i不等于3, 而是等于2。因 为A和B线程在更新变量i的时候拿到的i都是1, 这就是线程不安全的更新操作,通常我们会使 用synchronized来解决这个问题,synchronized会保证多线程不会同时更新变量i。 而Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以下简称Atomic包),这个包中 的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。 因为变量的类型有很多种,所以 在Atomic包里一共提供了13个类,属于4种类型的原子更 新方式,分别是原子更新基本类型、原子更新数组、原子更新引用和原子更新属性(字段)。 Atomic包里的类基本都是使用Unsafe实现的包装类。 原子更新基本类型类 使用原子的方式更新基本类型,Atomic包提供了以下3个类。 AtomicBoolean 原子更新布尔类型。 Atomiclnteger 原子更新整型。 AtomicLong 原子更新长整型。 以上3个类提供的方法几乎一模一样,所以本节仅以Atomiclnteger为例进行讲解,

11.Actomic原子类

南楼画角 提交于 2019-12-31 21:34:13
文章目录 1. 原子更新基本类型类 2. 原子更新数组 3. 原子更新引用类型 4. 原子更新字段类 1. 原子更新基本类型类 AtomicBoolean:原子更新布尔类型 AtomicInteger:原子更新整型 AtomicLong:原子更新长整型 常用方法如下: int addAndGet(int delta):以原子方式将输入的数值与实例中的值(AtomicInteger 里的 value)相加,并返回结果 boolean compareAndSet(int expect,int update):如果输入的数值等于预期值,则以原子方式将该值设置为输入的值 int getAndIncrement():以原子方式将当前值加1,注意,这里返回的是自增前的值 void lazySet(int newValue):最终会设置成 newValue,使用 lazySet 设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值 int getAndSet(int newValue):以原子方式设置为 newValue 的值,并返回旧值 原子性的设置原理:通过死循环+CAS实现 public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this