600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 【Java 并发编程】线程简介 ( 原子操作 | volatile 关键字使用场景 )

【Java 并发编程】线程简介 ( 原子操作 | volatile 关键字使用场景 )

时间:2023-01-06 18:26:30

相关推荐

【Java 并发编程】线程简介 ( 原子操作 | volatile 关键字使用场景 )

文章目录

一、原子操作二、volatile 关键字使用场景

一、原子操作

原子操作 :

read :从 主内存 中的线程共享变量中读取数据 ;

load :将从主内存读取到的数据 , 加载到 线程工作内存 中 ;

read 和 load 操作一定是 成对出现 的 , 只要从主内存中读取到数据 , 一定会将这个数据加载到线程的工作内存中 ;

use :从线程共享变量副本读取到线程的 执行引擎 中 ;

assign :从执行引擎中写出数据到变量的 共享变量副本 中 ;

store :将数据从线程工作内存传输到 主内存 中 ;

write :将数据赋值给主内容中的线程 共享变量 ;

lock :作用于 主内存中的线程共享变量 , 将该变量标识为 被某个线程独自占用状态 ; 表示该变量只有一个线程可以进行访问 ;

unlock :解锁 主内存中的共享变量 , 其它线程可以进行访问 ;

二、volatile 关键字使用场景

在下面的示例中 , 设置一个标志位 , 主线程开始后 , 启动一个线程 , 休眠 100010001000 毫秒 , 然后修改该标志位 , 主线程中根据标志位进行循环 , 如果标志位被修改 , 则循环停止 , 但是循环一直没有停止 ;

也就是说线程中修改的值 , 仅修改了该线程中工作内存中的标志位副本的值 ;

主内存中的值没有被修改 ;

代码示例 :

public class Main {private static boolean flag = false;private static void changeFlag() {System.out.println("修改标志位开始");flag = true;System.out.println("修改标志位结束");}public static void main(String[] args) {// 在该线程中 , 1 秒后修改标志位为 falsenew Thread(){@Overridepublic void run() {super.run();try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}changeFlag();}}.start();// 此处如果 flag 一直为 flase 就会进入死循环//如果 flag 为 true 则程序结束while (!flag) {}System.out.println("主线程结束");}}

执行结果 :

原理分析 :

线程的工作内存中 , 将flag修改为true, 这只是在 CPU 缓存 中修改的 , 没有在主内存中修改这个共享变量值 , 因此主线程访问该值 , 还是false;

使用 volatile 关键字 , 禁用 CPU 的缓存 , 直接在主内存中进行读写 , 这样就可以解决多个线程中 共享变量 不同步的问题 ;

注意 :只能是 线程共享变量 使用该关键字 , 设置该关键字会影响线程的执行效率 , 效率会降低 ;

使用了 volatile 关键字后的效果 :

public class Main {private static volatile boolean flag = false;private static void changeFlag() {System.out.println("修改标志位开始");flag = true;System.out.println("修改标志位结束");}public static void main(String[] args) {// 在该线程中 , 1 秒后修改标志位为 falsenew Thread(){@Overridepublic void run() {super.run();try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}changeFlag();}}.start();// 此处如果 flag 一直为 flase 就会进入死循环//如果 flag 为 true 则程序结束while (!flag) {}System.out.println("主线程结束");}}

执行结果 :

Java 并发的 333 特性 :

原子性 :每个操作都是 不可拆分的原子操作 ; 在线程中进行a++就不是原子操作 , 该操作分为 333 个步骤 , 首先从主内存中读取a变量 , 然后进行自增操作 , 最后在将自增后的值写回主内存中 ;可见性 :多个线程 访问同一个变量 , 该变量一旦被 某个线程修改 , 这些线程必须可以 立刻看到被修改的值 ;有序性 :程序按照 代码先后顺序 执行 ;

volatile 关键字 , 禁用了 CPU 缓存 , 解决的是共享变量可见性问题 ;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。