AtomicReference和AtomicLong、AtomicInteger很像,方法也基本上是一样的,然后我们通过引用Integer来做一个简单的例子。

com.mmall.concurrency.example.atomic.AtomicExample4

C:\Users\ZHONGZHENHUA\imooc\concurrency\src\main\java\com\mmall\concurrency\example\atomic\AtomicExample4.java

package com.mmall.concurrency.example.atomic;

import com.mmall.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.atomic.AtomicReference; @Slf4j
@ThreadSafe
public class AtomicExample4 {
private static AtomicReference<Integer> count = new AtomicReference<>(0); public static void main(String args[]){
count.compareAndSet(0,2); //
count.compareAndSet(0,1); // no
count.compareAndSet(1,3); // no
count.compareAndSet(2,4); //
count.compareAndSet(3,5); // no
log.info("count:{}",count.get()); }
}

AtomicIntegerFieldUpdater的核心是想原子性去更新某一个类的一个实例,就是我们这里说的example5,选定的某一个字段count,这个count值必须要求是通过特殊关键字修饰才可以,这个类的本质上就是干这个事情的,是原子性的修改。如果当前的这个变量example5对应的这个字段count,expect和update其实是id的版本支持的。如果我这里面传入的值是一个普通的数值,而不是定义好的一个常量值的时候,它就会告诉我当前这个变量是什么名称,这与我当前的id有关系,不是什么特殊的配置。AtomicIntegerFieldUpdater它的核心作用是要更新指定的一个类AtomicExample5的某一个字段的值,而这个字段它要求必须是通过volatile修饰同时还不能是static的字段才可以。这是它的要求,必须是有这个volatile以及非static描述的字段才可以。AtomicIntegerFieldUpdater使用的不多。com.mmall.concurrency.example.atomic.AtomicExample5

C:\Users\ZHONGZHENHUA\imooc\concurrency\src\main\java\com\mmall\concurrency\example\atomic\AtomicExample5.java

package com.mmall.concurrency.example.atomic;

import com.mmall.concurrency.annoations.ThreadSafe;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; @Slf4j
@ThreadSafe
public class AtomicExample5 { private static AtomicIntegerFieldUpdater<AtomicExample5> updater = AtomicIntegerFieldUpdater.newUpdater(AtomicExample5.class,"count"); @Getter
public volatile int count = 100; private static AtomicExample5 example5 = new AtomicExample5(); public static void main(String args[]){
if (updater.compareAndSet(example5,100,120)){
log.info("update success 1, {}",example5.getCount()); }
if (updater.compareAndSet(example5,100,120)){
log.info("update success 2, {}",example5.getCount());
}else{
log.info("update failed, {}",example5.getCount());
}
}
}
 

 ABA问题它是指在CAS操作的时候,其他线程将变量的值A改成了B,但是又改回了A,本线程使用期望值A与当前变量进行比较的时候,发现A变量没有变,于是CAS就将A值进行了交换操作。这个时候实际上该值已经被其他线程改变过,这与实际思想是不符合的。因此ABA问题的解决思路它是每次变量更新的时候,把变量的版本号加1,那么之前的那个A改成B再改成A,就会变成了A对上1版本,然后改成B变成2版本,再改回A变成3版本。这个时候只要变量被某一个线程修改过,该变量对应的版本号就会发生递增变化,从而解决了ABA问题。


java.util.concurrent.atomic.AtomicStampedReference的核心方法是compareAndSet,这个方法里相对于我们之前的java.util.concurrent.atomic.AtomicBoolean的compareAndSet多了一个stamp的比较。stamp的值是由每次更新的时候来维护的,它的使用和我们之前其他Atomic包里面的其他类的用法很相似。

    /**
* Atomically sets the value of both the reference and stamp
* to the given update values if the
* current reference is {@code ==} to the expected reference
* and the current stamp is equal to the expected stamp.
*
* @param expectedReference the expected value of the reference
* @param newReference the new value for the reference
* @param expectedStamp the expected value of the stamp
* @param newStamp the new value for the stamp
* @return {@code true} if successful
*/
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}

java.util.concurrent.atomic.AtomicLongArray 它维护的是一个数组,这个数组我们可以选择性地更新某一个索引对应的值,也是进行原子性操作的。相比于AtomicLong和AtomicInteger它们的方法,它的方法会额外多一个索引值让我们去更新。getAndSet,取出这个索引更新一个值。compareAndSet也是,它这里面相当于举了一个实例之后呢,传入对应是哪个索引的值,告诉我期望是哪个值,更新成哪个值。


 java.util.concurrent.atomic.AtomicBoolean的compareAndSet在实际中还是很实用的。

因为它的原子性操作,它可以保证从false变成true只会执行一次,之后的所有4999次,在主要这个函数if(isHappened.compareAndSet(false,true)){判断的时候呢,都是因为它是true没法执行这个动作因此都不会执行。当前这个例子演示了我们如何让某一段代码只执行一次,绝对不会重复,在实际中有的时候会遇到有些流程你只希望某一段代码只执行过一遍就可以参考这个例子来去处理它。

com.mmall.concurrency.example.atomic.AtomicExample6

C:\Users\ZHONGZHENHUA\imooc\concurrency\src\main\java\com\mmall\concurrency\example\atomic\AtomicExample6.java

package com.mmall.concurrency.example.atomic;

import com.mmall.concurrency.annoations.ThreadSafe;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean; @Slf4j
@ThreadSafe
public class AtomicExample6 { private static AtomicBoolean isHappened = new AtomicBoolean(false); // 请求总数
public static int clientTotal = 5000;//1000个请求 // 同时并发执行的线程数
public static int threadTotal = 200;//允许并发的线程数是50 //public static AtomicBoolean count = new AtomicBoolean(false); public static void main(String args[]) throws Exception{
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(threadTotal);
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal; i++) {
executorService.execute(()-> {
try {
semaphore.acquire();
//add();
test();
semaphore.release();
} catch (Exception e) {
log.error("exception",e);
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
//log.info("count:{}",count);
//log.info("count:{}",count.get());
log.info("isHappened:{}",isHappened.get()); }
public static void test(){
if(isHappened.compareAndSet(false,true)){
log.info("execute"); }
}
}

使用Atomic包下面的AtomicInteger的类可以实现线程安全,在这个基础之上呢跟大家说明了CAS原理,以及实现的时候借助于UnSafe的compareAndSwapInt这个方法。AtomicLong和LongAdder这两个类的使用以及它们的对比,它们的优势和缺点。AtomicReference和AtomicReferenceUpdater两个类的使用。AtomicStampReference来解决掉CAS的ABA问题。AtomicLongArray这个类的使用,AtomicBoolean的compareAndSet方法在实际中的应用。



4-2 线程安全性-原子性-atomic-2的更多相关文章

  1. 并发与高并发(七)-线程安全性-原子性-atomic

    一.线程安全性定义 定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程 ...

  2. Java并发编程入门与高并发面试(三):线程安全性-原子性-CAS(CAS的ABA问题)

    摘要:本文介绍线程的安全性,原子性,java.lang.Number包下的类与CAS操作,synchronized锁,和原子性操作各方法间的对比. 线程安全性 线程安全? 线程安全性? 原子性 Ato ...

  3. 线程安全性-原子性之Atomic包

    先了解什么是线程安全性:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称为这个类是线程 ...

  4. 4-3 线程安全性-原子性-synchronized

    原子性它提供了互斥访问,同一时刻只能有一个线程来对它进行操作.能保证同一时刻只有一个线程来对其进行操作的,除了Atomic包之外,还有锁.JDK提供锁主要分两种,synchronized是一个Java ...

  5. 线程安全性-原子性之synchronized锁

    原子性提供了互斥访问:同一时刻只能有一个线程进行操作: 除了Atomic包类之外,还有锁可以实现此功能: synchronized:  java关键字,依赖于jvm实现锁功能,被此关键字所修饰的,都是 ...

  6. 4-1 线程安全性-原子性-atomic-1

    我们发现在不做任何同步的情况下,我们计算的累加结果是错误的. com.mmall.concurrency.example.count.CountExample2 C:\Users\ZHONGZHENH ...

  7. 并发与高并发(八)-线程安全性-原子性-synchronized

    前言 闲暇时刻,谈一下曾经在多线程教程中接触的同步锁synchronized,相当于复习一遍吧. 主要介绍 synchronized:依赖JVM Lock:依赖特殊的CPU指令,代码实现,Reetra ...

  8. Java线程安全性-原子性工具对比

    synchronized 不可中断锁,适合竞争不激烈的场景,可读性好,竞争激烈时性能下降很快 Lock 可中断锁,多样化同步,竞争激烈时能维持常态 Atomic 竞争激烈时能维持常态,比Lock性能还 ...

  9. Java并发编程 (四) 线程安全性

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.线程安全性-原子性-atomic-1 1.线程安全性 定义: 当某个线程访问某个类时,不管运行时环境 ...

随机推荐

  1. oracle的序列号(sequence)

    oracle的自增列,要采用序列号(sequence). 初始化阶段要手动建立一个sequence,然后插入的时候,还要手动自己去读这个sequence的nextval赋给相关字段,如ID,麻烦的很. ...

  2. 1 秒杀系统模拟基础实现,使用DB实现

    本文根据动脑学院的一节类似的课程,改编实现.分别使用DB和redis来完成. 隔离的解释 业务隔离:将秒杀业务独立出来,尽量不与其他业务关联,以减少对其他业务的依赖性.譬如秒杀业务只保留用户id,商品 ...

  3. [置顶] Android 适配真要命?

    原始尺寸场景 相信大家对上面也有所有耳闻另外就是如何计算屏幕的密度一般都是按照勾股定理例如中等屏幕密度 480^2+800^2开根号 然后除以当前屏幕尺寸3.5-4.2之间尺寸. 对于刚出来的那些An ...

  4. 原生JavaScript获取css样式

    访问属性:obj.attr 或者 obj['attr'] 通过js访问style属性 : document.getElementById("main").style.backgro ...

  5. 微信小程序转支付宝小程序

    使用方法: npm install wx-alipay -g wxToalipay --src={{小程序源码目录}} --dest={{支付宝小程序目录,可缺省}} 点击回车后就可将微信小程序转换为 ...

  6. cordic算法的fpga实现

    cordic算法参考:http://wenku.baidu.com/view/6c623aa8910ef12d2bf9e732.html 这是百度文库的一个文档,详细介绍了cordic算法的基本内容. ...

  7. Python的Django框架中if标签的相关使用

    {% if today_is_weekend%} {% end if %} 系统会显示在这之间的内容 {% else %}标签是可选的 在python和django模板系统中,以下对象相当于布尔值的F ...

  8. C#获取文件的MD5码

    using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace Send ...

  9. 实现一个自定义<table>标签

    需求是有两个自定义的标签<table>和<column> <table>有个items属性,负责导入数据 package hello; import java.ut ...

  10. ORMLite的使用

    首先需要下载core和android两个jar http://ormlite.com/releases/ 然后拷贝到libs文件夹下并且添加为库 具体的使用看标程: School.java packa ...