JDK多线程基础(4):Java内存模型与 Volatile

Java 内存模型

主内存与线程工作内存

  1. 主内存:所有线程共享,存放共享变量
  2. 线程工作内存:每一个线程有一块工作内存区,存放着共享变量的拷贝。当线程执行时,它在自己的工作内存中操作这些变量,其他线程不可见

工作内存与主内存交互

  1. 一个线程可以执行的操作有使用(use)、赋值(assign)、装载(load)、存储(store)、锁定(lock)、解锁(unlock)。主内存可以执行的操作有读(read)、写(write)、锁定(lock)、解锁(unlock),每一个操作都是原子的
  2. 主内存和工作内存间的数据传送并不满足原子性:需要两个步骤
  • 主内存复制到工作内存
    • 由主内存执行的读(read)操作
    • 由工作内存执行的装载(load)操作
  • 工作内存拷贝到主内存
    • 工作内存执行存储(store)操作
    • 主内存执行写(write)操作
  1. 由于主内存和工作内存间传输数据需要时间,且该时间不确定。因此从另一个线程的角度看,可能会存在值不同步的现象
  • 两个线程把不同的值或者对象引用存储到同一个主内存中的共享变量中,该变量那么是这个线程的,那么是那个线程
  • 但是 long、double 这种类型的变量,有可能会是两个线程组合而成
  1. 使用 Volatile 关键字迫使所有线程均读写主内存中对应的变量,从而使得 Volatile 变量在多线程间可见

线程内存操作

Volatile 关键字

关键字分析

  1. 使用 Volatile 标识变量,将迫使所有线程均读写主内存中的对应变量,从而使得 Volatile 变量在多线程间可见
  2. 当前线程对 Volatile 修饰变量的修改,能即时写回共享主内存中,并被其他线程所见
  3. 其他线程对 Volatile 修饰变量的修改,可以即时反应到当前线程中
  4. 使用 Volatile 修饰的变量,编译器会保证其有序性

Volatile 使用方法

  1. 帮助理解的例子
public class VolatileUse {

    private volatile boolean isExit;

    public void tryExit() {
        // 成立就退出
        if (isExit == !isExit) {
            System.exit(0);
        }
    }

    public void swapValue() {
        isExit = !isExit;
    }

    public static void main(String[] args) throws InterruptedException {
        final VolatileUse volatileUse = new VolatileUse();
        Thread mainThread = new Thread() {
            @Override
            public void run() {
                System.out.println("Main Thread start");
                while (true) {
                    // 不停的尝试时候可以退出
                    volatileUse.tryExit();
                }
            }
        };

        mainThread.setName("Main Thread");
        mainThread.start();

        Thread swapThread = new Thread() {
            @Override
            public void run() {
                System.out.println("Swap Thread start");
                while (true) {
                    // 不停的修改 isExit 的值
                    volatileUse.swapValue();
                }
            }
        };

        swapThread.setName("Swap Thread");
        swapThread.start();
        Thread.sleep(10000L);
    }
}

  1. 常用方法:
  • 线程因为 stop 变量改变而退出
  • volatile 的意义在于在主线程中停止 InThread 线程,这 InThread 会立即发现 stop 状态的改变,从而停止
public class VolatileThread {

    public static void main(String[] args) throws InterruptedException {
        InThread inThread = new InThread();
        new Thread(inThread, "Volatile Thread ").start();
        Thread.sleep(1000);
        inThread.stop();
        Thread.sleep(1000);
    }


    static class InThread implements Runnable {

        /**
         * 确保 stop 变量在多线程中可见
         */
        private volatile boolean stop = false;

        /**
         * 在其他线程中调用,停止本线程
         */
        public void stop() {
            this.stop = true;
        }

        @Override
        public void run() {
            int i = 0;
            while (!stop) {
                i++;
            }
            System.out.println("Stop Thread " + i);
        }
    }
}
  1. 结论:
    当多个线程同时访问一个共享变量时,可以使用 volatile,而当访问的变量已在 synchronized 代码块中时,不必使用

参考

  1. 源码地址

Fork me on Gitee

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值