多线程之volatile的使用

在java中,每一个线程都一个独立的工作内存,各个线程的工作内存之间相互独立、互不可见,工作内存中的变量的数据值都是事先从主内存中拷贝的,当线程执行时候,就会在工作内存中操作这些变量的值,最后当线程执行完毕,就会将这些变量的值推送给主内存。
对于volatile修饰的变量而言, 只要在任何工作内存中发生改变就会被强制刷新到主内存中去,然后其他线程的工作内存重新在主内存中获取该变量的值。

这里写图片描述

volatile使得线程之间数据可见

首先看下面的案例:

package com.wuk.diryRead;

public class MyThread001 extends Thread{

    private boolean  isRunning=true;
    private void setRunning(boolean  isRunning) {

        this.isRunning=isRunning;
    }

    @Override
    public void run() {

        System.out.println("进入run方法。。。。");
        while(isRunning) {      

        }
        System.out.println("线程停止");
    }

    public static void main(String[] args) {

        MyThread001 t1=new MyThread001();
        t1.start();
        try {
            Thread.sleep(3000);
            t1.setRunning(false);
            System.out.println("主线程已经将isRunning设置成false了");
            Thread.sleep(1000);
            System.out.println(t1.isRunning);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }
}

运行结果

进入run方法。。。。
主线程已经将isRunning设置成falsefalse

当main方法已经将判断条件isRunning变量的值变成了false,但是在t1线程的工作内存中isRunning的值还是true,所以线程肯定还会一直执行下去。

当我将变量写成如下:

private volatile boolean  isRunning=true;

运行结果如下:

进入run方法。。。。
主线程已经将isRunning设置成false了
线程停止
false`

volatile只具备可见性 而不具备synchronized的原子性

案例:

public class MyThread003  extends Thread{

    private static volatile int count;
    //private static AtomicInteger  count=new AtomicInteger(0);

    private static void addCount() {

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

            count++;
            //count.incrementAndGet();
        }

        System.out.println(count);
    }



    @Override
    public void run() {

        addCount();
    }



    public static void main(String[] args) {

        MyThread003[] arr=new MyThread003[10];
        for(int i=0;i<arr.length;i++) {

            arr[i]=new MyThread003();

        }

        for(int i=0;i<10;i++) {

            arr[i].start();
        }
    }
}

打印结果

4078
4078
4078
4078
4078
5078
6126
8365
7903
6832

咱们不看前面的值怎么样,因为Java的打印函数具有一定的延迟性, 只看最后一个值,如果volatile具有原子性,那么最后一个结果应当是10000,因为volatile如果在对volatile修饰的数据进行操作时候,如果具备原子性的话,此时对它进行操作的线程只能有一个,这样10个线程累计下来最后一个数据应当是10000,而现在显然不是,那就证明中间有多线程同时操作这个变量,导致最后结果非10000.

如果我们想保证数据的原子性,那么采用上面注释的AtomicInteger 类,它具有原子性,可以使得线程同步操作数据。

注意:AtomicInteger 的多个addAndGet()在同一个方法内是非原子性,需要加上synchronized修饰。

案例

private static void addCount() {

        for(int i=0;i<1000;i++) {
            count.addAndGet(1);
            count.addAndGet(2);
            count.addAndGet(3);
            count.addAndGet(4);
        }

要想保证每次加10那么久需要给该方法加上一个synchronized。

所以综上,我们可以得到volatile的结论是:volatile修饰的数据在线程之间具备可见性,但是他不具备数据的原子性。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术闲聊DD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值