java中volatile关键字---学习笔记

本文深入解析Java中volatile关键字的作用,探讨其在确保变量可见性的同时为何无法保证操作的原子性,通过示例代码验证这一特性,并给出线程安全的定义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

volatile关键字的作用
在java内存模型中,线程之间共享堆内存(对应主内存),但又各自拥有自己的本地内存——栈内存,线程的栈内存中缓存有共享变量的副本,但如果是被volatile修饰的变量,线程每次都直接从堆内存中读取最新值,并在操作完成时将新值写入堆内存。

但需要注意的一点是:volatile关键字只能保证主存中的变量值是最新的,并不能保证操作的原子性,因此它不能代替synchronized。像简单的i++也不是原子操作,它包括了read(i),inc(i),write(i)的过程,可能:当一个线程刚从主存中读取出i的最新值还未进行下一步操作时,另一个线程正往主存中写入新值,此时就会出现线程不安全的情况。

什么是线程安全?
通俗的解释就是:有多个线程在同时运行一段代码,如果每次运行的结果和单线程运行的结果一样,而且其他的变量值也和预期的一样,这样叫做线程安全。例子:一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。

volatile拥有可见性但是不具有原子性的验证
这里通过创建1000个线程对同一个计数器Counter进行++操作来验证volatile的线程安全性。为了排除main thread最后读取count值时,尚有线程没有结束的情况,这里引入 Java concurrent包里面的一个同步辅助类CountDownLatch,通过countDown()方法和await()方法来保证main thread最后读取到的count值是主存中最新的。

CountDownLatch latch = new CountDownLatch(1000); //用给定的计数次数1000进行初始化。
latch.countDown(); //此操作是原子操作,即同时只允许有一个线程去减这个计数器里面的值。
latch.await();//在计数器latch里面的值变为0之前一直处于阻塞状态。

import java.util.concurrent.CountDownLatch;

public class Counter {

    public volatile static int count = 0;
    CountDownLatch latch = new CountDownLatch(1000); 

    public static void inc() {
        count++;
    }

  //1000 threads start simultaneously for i ++ calculations, to see the actual results ;
    public void test() throws InterruptedException {
         for (int i = 0; i < 1000; i++) {
             new Thread(new Runnable() {
                 @Override
                 public void run() {
                     Counter.inc();
                 }
             }).start();
             latch.countDown(); //Ensure that all threads have been completed ;
             System.out.println("Come here " + (i + 1) + " times");
         }
         latch.await(); //Until 1000 threads complete before reading the counter value inside ;
         System.out.println(Thread.currentThread().getName() + " thread : " + Counter.count);
    }
  //Here the value of each run are likely to differ , possibly 1000 ;

    public static void main(String[] args) {

        try {
            new Counter().test();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

运行结果:
这里写图片描述

测试结果说明:java中的volatile关键字只可保证读取可见性但并不是线程安全的,在实际使用过程中,我们要具体情况具体分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值