栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java Volatile变量说明与测试

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java Volatile变量说明与测试

Volatile 字段

Volatile 字段为实例字段的同步访问提供了一种免锁机制。如果声明一个字段为 volatile ,那么编译器和虚拟机就知道该字段可能被另一个线程并发更新。

编译器会插入适当的代码,以确保 如果一个线程对 volatile变量做了修改,这个修改对读取这个变量的所有其它线程可见。

public class Class2 {
    private volatile int x;
    public void count(){
        x++;
    }
    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }
}
public static void main(String[] args) {
    Class2 class2 = new Class2();
    Thread thread1 = ThreadFactory.createThreadByRunnable(() -> {
        try {
            Thread.sleep(10); //让另一个线程启动
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (true){
            int x = class2.getX();
            class2.count(); //使x的值加一
            if (class2.getX() < x){ //如果其它线程修改了x变量,则输出修改前后的值
                System.out.printf("%s counted %d || %dtn",Thread.currentThread(),class2.getX(),x);
            }
        }
    });
    Thread thread2 = ThreadFactory.createThreadByRunnable(() -> {
        while (true) {
            int x = class2.getX();
            System.out.print(Thread.currentThread() + ":");
            class2.setX(x); //修改x的值
            System.out.printf("SET x%dtn", x);

        }
    });
    thread1.start();
    thread2.start();
}

运行结果部分截图

  • counted 后的两个数字分别表示 现在x的值 以及 该线程最初获得的x的值

第二行的输出结果分析:

  • 第19行代码执行后,线程由 thread2 切换至 thread1,然后在 thread1 停留一段时间后再次切换至 thread2
    • 此时 thread2 中的 x 已经和当前的 x 有了偏差
  • 第21行代码执行后( 修改了x 变量),线程由 thread2 切换至 thread1,代码在 thread1 中运行至12行
    • 发现 x 变量发生了修改,随后输出修改前后的值,线程此时再次切换至 thread2
  • 执行第22行代码,并输出修改的值,可以发现 其修改的值和 thread1 获取的完全一样

结论

Volatile 字段 可以保证变量在并发时的内存可见性,但并不提供原子性

一个线程如果多次读取Volatile 字段,其前后的值可能发生改变

如果去掉 volatile 声明,则运行结果如下

thread1 将无法检查到变量x 的修改

补充

  • 每个线程都有一个工作缓存副本
public class MyThread implements Runnable{
    boolean flag = true;
    //boolean volatile flag = true;
    @Override
    public void run() {
        System.out.println("Enter in " + Thread.currentThread());
        int i = 0;
        while (flag){
            i++;
        }
        System.out.println(Thread.currentThread() + "is exiting");
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        new Thread(thread).start();
        Thread.sleep(1000);
        thread.flag = false;
        System.out.println("main is exiting");
    }
}
  • 若 该线程比main线程先启动,那么将陷入死循环(无 volatile 修饰)
    • 其 flag 的值仍是其工作缓存内的值
  • Volatile 字段解决了工作副本的可见性问题
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/693915.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号