聊聊 volatile 关键字

代码星冰乐

专注成就未来

首页 归档 关于

聊聊 volatile 关键字

Oct 19, 2018 | haifeiWu | Java | 阅读
文章目录
  1. 1. 算法概念及其执行流程
  2. 2. CAS 操作过程如下所示
  3. 3. CAS 算法模拟
  4. 4. 原子变量
  5. 5. 原子变量简单 Demo
  6. 6. 小结

作 者:haifeiWu
原文链接:https://www.hchstudio.cn/article/2018/3da/
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。


由于版权原因,请阅读原文 --> 聊聊 volatile 关键字

关注我们

作 者:haifeiWu
原文链接:https://www.hchstudio.cn/article/2018/3da/
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

作 者:haifeiWu
原文链接:https://www.hchstudio.cn/article/2018/3da/
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

我们知道 volatile 关键字的作用是保证变量在多线程之间的可见性,它是 java.util.concurrent 包的核心,没有 volatile 就没有这么多的并发类给我们使用。本文将简单介绍一下 volatile 这个东东。

算法概念及其执行流程

  • CAS(compare-and-swap) 是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问。
  • CAS 是一种无锁非阻塞算法的实现。
  • CAS 包含了 3 个操作数:
    需要读写的内存值 V
    进行比较的值 A
    拟写入的新值 B

  • 当且仅当 V 的值等于 A 时,CAS 通过原子方式用新值更新 V 的值,否则不会执行任何操作。

CAS 操作过程如下所示

CAS操作过程

CAS 算法模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 模拟 CAS 算法
*
* Created by wuhf on 2017-1-22.
*/
public class TestCompareAndSwap {
public static void main(String[] args){
final CompareAndSwap cas = new CompareAndSwap();

for (int i = 0; i < 10; i++ ){
new Thread(new Runnable() {
@Override
public void run() {
int expectValue = cas.getValue();
boolean b = cas.compareAndSet(expectValue, (int)(Math.random() * 101));
System.out.println(b);
}
}
).start();
}
}
}

class CompareAndSwap{
private int value;

// 获取内存值
public synchronized int getValue(){
return this.value;
}
// 比较
public synchronized int compareAndSwap(int expectValue,int newValue){
int oldValue = this.value;
if(oldValue == expectValue){//如果期望值等于旧值
this.value = newValue;
}
return oldValue;
}

public synchronized boolean compareAndSet(int expectValue,int newValue){
return expectValue == compareAndSwap(expectValue, newValue);
}

}

原子变量

  • 类的小工具包,支持在单个变量上解除锁的线程安全编程。事实上,此包中的类可将 volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类。

  • 类 AtomicBoolean、 AtomicInteger、 AtomicLong 和 AtomicReference 的实例各自提供对相应类型单个变量的访问和更新。每个类也为该类型提供适当的实用工具方法。

  • AtomicIntegerArray、 AtomicLongArray 和 AtomicReferenceArray 类进一步扩展了原子操作,对这些类型的数组提供了支持。这些类在为其数组元素提供 volatile 访问语义方面也引人注目,这对于普通数组来说是不受支持的。

  • 核心方法: boolean compareAndSet(expectedValue, updateValue)

  • java.util.concurrent.atomic 包下提供了一些原子操作的常用类:

  1. AtomicBoolean 、 AtomicInteger 、 AtomicLong 、AtomicReference
  2. AtomicIntegerArray 、 AtomicLongArray
  3. AtomicMarkableReference
  4. AtomicReferenceArray
  5. AtomicStampedReference

原子变量简单 Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 一、i++ 的原子性问题:i++ 的操作实际上分为三个步骤“读-改-写”
* int i = 10;
* i = i++; //10
*
* int temp = i;
* i = i + 1;
* i = temp;
* 二、原子变量:在 java.util.concurrent.atomic 包下提供了一些原子变量。
* 1. volatile 保证内存可见性
* 2. CAS(Compare-And-Swap) 算法保证数据变量的原子性
* CAS 算法是硬件对于并发操作的支持
* CAS 包含了三个操作数:
* 1,内存值 V
* 2,预估值 A
* 3,更新值 B
* 当且仅当 V == A 时, V = B; 否则,不会执行任何操作。
*/
public class AtomicDemo {
public static void main(String[] args) {
AtomicData ad = new AtomicData();
for (int i = 0; i < 10; i++) {
new Thread(ad).start();
}
}
}

class AtomicData implements Runnable{
// 初始化原子变量
private AtomicInteger atomicData = new AtomicInteger(0);

@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println(getAtomicData());
}

// 相当于atomicData++
public int getAtomicData(){
return atomicData.getAndIncrement();
}

}

小结

在我们的实现可能会被并发操作的共享资源时,加锁可能会是最简单粗暴的方法,但是使用不慎必然会产生死锁等问题,而造成线程假死,产生重大线上问题。因此 volatile 不失为不错的选择。

关注我们

作 者:haifeiWu
原文链接:https://www.hchstudio.cn/article/2018/3da/
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

分享
Java源码解析
安全闲扯Filter 设计模式编码实践
微信关注我们
分类
  • Android8
  • Go4
  • Java59
  • Kafka,Java1
  • Kotlin2
  • Linux1
  • MapReduce1
  • Python2
  • Raft1
  • Redis1
  • ThreadPoolExecutor1
  • go1
  • 工具1
  • 总结8
  • 旅游日记1
标签
Nginx ChanghuiN haifeiWu Android Java 设计模式 hexo Kotlin 算法 MySQL 源码解析 Python Redis golang web Kafka 配置中心 总结 性能优化 旅游日记 Shell Go 问题排查 译文 Docker Spring Boot 工具 学习笔记 WebFlux 性能测试 go 散列表 源码 netty Raft
最近文章
  • Kafka的日志复制机制
  • 从20到21
  • go 并发编程
  • 【译】了解Linux CPU负载-您何时应该担心?
  • Zookeeper 与分布式锁
  • 基于Redis的分布式锁到底安全吗?
  • 【译】Raft 学生指南
  • ThreadPoolExecutor 的简单梳理
  • MapReduce 的简单实现
  • 使用 Map 实现策略模式
福利专区
    免费SSL证书
      阿里云红包
        腾讯云专属福利
        Copyright © 2021 代码星冰乐. Powered by ChanghuiN. 版权所有 晋ICP备15001365号
        特别感谢: 云服务器服务商 、 CDN 服务商