零基础java自学流程-Java语言高级317

本文探讨了volatile关键字在Java中的使用场景及其限制。volatile可以确保变量的可见性和代码的有序性,但在多线程环境下,volatile不能保证变量操作的原子性。通过一个计数器增加的例子说明了即使使用volatile,由于自增操作的非原子性仍可能导致并发问题。

volatile使用场景

volatile的可以在以下场景中使用:

当运算结果不依赖变量当前的值,或者能确保只有单一线程修改变量的值的时候,我们才可以对该变量使用volatile关键字
变量不需要与其他状态变量共同参与不变约束

volatile与原子性

volatile关键字能保证变量的可见性和代码的有序性,但是不能保证变量的原子性,下面我再举一个volatile与原子性的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public class VolatileTest {

 public static volatile int count = 0;

 public static void increase() {

  count++;

 }

 public static void main(String[] args) {

  Thread[] threads = new Thread[20];

  for(int i = 0; i < threads.length; i++) {

   threads[i] = new Thread(() -> {

    for(int j = 0; j < 1000; j++) {

     increase();

    }

   });

   threads[i].start();

  }

  //等待所有累加线程结束

  while (Thread.activeCount() > 1) {

   Thread.yield();

  }

  System.out.println(count);

 }

}

上面这段代码创建了20个线程,每个线程对变量count进行1000次自增操作,如果这段代码并发正常的话,结果应该是20000,但实际运行过程中经常会出现小于20000的结果,因为count++这个自增操作不是原子操作。

上面的count++自增操作等价于count=count+1,所以JVM需要先读取count的值,然后在count的基础上给它加1,然后再将新的值重新赋值给count变量,所以这个自增总共需要三步。

 

上图中我将线程对count的自增操作画了个简单的流程,一个线程要对count进行自增时要先读取count的值,然后在当前count值的基础上进行count+1操作,最后将count的新值重新写回到count。

如果线程2在线程1读取count旧值写回count新值期间读取count的值,显然这个时候线程2读取的是count还未更新的旧值,这时两个线程是对同一个值进行了+1操作,这样这两个线程就没有对count实现累加效果,相反这些操作却又没有违反volatile的定义,所以这种情况下使用volatile依然会存在多线程并发安全的问题。


尚学堂给同学们带来全新的Java300集课程啦!java零基础小白自学Java必备优质教程_手把手图解学习Java,让学习成为一种享受_哔哩哔哩_bilibili尚学堂给同学们带来全新的Java300集课程啦本课程为Java300集2022版第一季,配合最新版的Java课程,所有视频重新录制,课件所有图形做了重新绘制和配色,图解学习Java,让学习成为一种享受本套教程专门为零基础学员而制,适合准备入行Java开发的零基础学员,视频中穿插多个实战项目。每一个知识点都讲解的通俗易懂,由浅入深。不仅适用于零基础的初学者,有经验的程序员也可做巩固学习。后续课https://www.bilibili.com/video/BV1qL411u7eE?spm_id_from=333.999.0.0

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值