原子性已经说了,下面说下可见性。可见性其实和 Java 内存模型的设定有关:Java 内存模型规定所有的变量都是存在主存(线程共享区域)当中,每个线程都有自己的工作内存(私有内存)。线程对变量的所有操作都必须在工作内存中进行,而不直接对主存进行操作。并且每个线程不能访问其他线程的工作内存。举个简单栗子:比如上面 i 操作,在 Java 中,执行 i 语句:执行线程首先从主存中读取 i(原始值)到工作内存中,然后在工作内存中执行运算 1 操作(主存的 i 值未变),最后将运算结果刷新到主存中。

数据运算是在执行线程的私有内存中进行的,线程执行完运算后,并不一定会立即将运算结果刷新到主存中(虽然最后一定会更新主存),刷新到主存动作是由 CPU 自行选择一个合适的时间触发的。假设数值未更新到主存之前,当其他线程去读取时(而且优先读取的是工作内存中的数据而非主存),此时主存中可能还是原来的旧值,就有可能导致运算结果出错。

以下代码是测试代码:package com.wupx.test;/*** @author wupx* @date 2019/10/31*/public class VolatileTest {private boolean flag = false;class ThreadOne implements Runnable {@Overridepublic void run() {while (!flag) {System.out.println("执行操作");try {Thread.sleep(1000L);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("任务停止");}}class ThreadTwo implements Runnable {@Overridepublic void run() {try {Thread.sleep(2000L);System.out.println("flag 状态改变");flag = true;} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {VolatileTest testVolatile = new VolatileTest();Thread thread1 = new Thread(testVolatile.new ThreadOne());Thread thread2 = new Thread(testVolatile.new ThreadTwo());thread1.start();thread2.start();}}上述结果有可能在线程 2 执行完 flag = true 之后,并不能保证线程 1 中的 while 能立即停止循环,原因在于 flag 状态首先是在线程 2 的私有内存中改变的,刷新到主存的时机不固定,而且线程 1 读取 flag 的值也是在自己的私有内存中,而线程 1 的私有内存中 flag 仍未 false,这样就有可能导致线程仍然会继续 while 循环。

运行结果如下:执行操作执行操作执行操作flag 状态改变任务停止避免上述不可预知问题的发生就是用 volatile 关键字修饰 flag,volatile 修饰的共享变量可以保证修改的值会在操作后立即更新到主存里面,当有其他线程需要操作该变量时,不是从私有内存中读取,而是强制从主存中读取新值。即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

指令重排序一般来说,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。比如下面的代码int i = 0;boolean flag = false;i = 1; // 1flag = true; // 2代码定义了一个 int 型变量,定义了一个 boolean 类型变量,然后分别对两个变量进行赋值操作。

从代码顺序上看,语句 1 是在语句 2 前面的,那么 JVM 在真正执行这段代码的时候会保证语句 1 一定会在语句 2 前面执行吗?不一定,为什么呢?这里可能会发生指令重排序(InstructionReorder)。语句 1 和语句 2 谁先执行对最终的程序结果并没有影响,那么就有可能在执行过程中,语句 2 先执行而语句 1 后执行。

但是要注意,虽然处理器会对指令进行重排序,但是它会保证程序最终结果会和代码顺序执行结果相同,那么它靠什么保证的呢?再看下面一个例子:int a = 10; // 1int r = 2; // 2a = a 3; // 3r = a * a; // 4这段代码执行的顺序可能是 1-

 3/3   首页 上一页 1 2 3 下一页

文章TAG:关键字  查重  摘要  论文  什么是论文摘要和关键字  关键字查重是什么  
下一篇