目录

chen 的个人博客

VX:TiAmo151028
Phone:13403656751
Email:zxydczzs@gmail.com

volatile关键字与内存可见性

 1package com.zxy.demo.thread;
 2
 3import lombok.Data;
 4
 5/**
 6 * @author ZhangXiaoYu
 7 * @date 2021/9/2 9:26
 8 */
 9public class ThreadDemo1 {
10    //volatile关键字与内存可见性
11    /*
12    * new一个线程子类实例并start,线程内部睡眠200毫秒后将flag设置为true
13    * 主线程使用while循环,如果线程子类的成员变量flag为true时,输出一句话后break出循环。
14    * 问题1:在主线程while循环时,flag已经为true,却没有跳出循环,为什么?
15    * 这是内存可见性的问题。当多个线程操作共享数据时,彼此不可见。
16    * 基本可以理解为,ThreadDemo线程先从主存中把数据读取过来,读取到的是false,然后修改为true,就在还未来得及把true同步到主存
17    * 时,main进来了,这是main读取到的还是false,所以形成死循环,就在main循环时,ThreadDemo线程把true同步到主存了,所以
18    * ThreadDemo线程中输出语句打印的是true。
19    *
20    * 要解决这个问题,可以加锁。
21    * */
22    public static void main(String[] args) throws InterruptedException { //这个线程是用来读取flag的值的
23        ThreadDemo threadDemo = new ThreadDemo();
24        Thread thread = new Thread(threadDemo);
25        thread.start();
26        //加锁处理
27        /*
28        * 加了锁,就可以让while循环每次都从主存中去读取数据,这样就能读取到true了,但是一旦加了锁,每次只能有一个线程访问,
29        * 当一个线程持有锁时,其他的就会阻塞,效率就非常低了,不想加锁,又要解决内存可见性问题,那么就可以使用volatile关键字。
30        * */
31//        while (true) {
32//            synchronized (threadDemo){
33//                if (threadDemo.isFlag()) {
34//                    System.out.println("主线程读取到的flag = " + threadDemo.isFlag());
35//                    break;
36//                }
37//            }
38//        }
39        //原始步骤
40        while (true) {
41            if (threadDemo.isFlag()) {
42                System.out.println("主线程读取到的flag = " + threadDemo.isFlag());
43                break;
44            }
45        }
46    }
47}
48@Data
49class ThreadDemo implements Runnable { //这个线程是用来修改flag的值的
50
51    /*
52    * volatile关键字:当多个线程操作共享数据时,可以保证内存中的数据可见,用这个关键字修饰共享数据,就会及时的把线程缓存中的数据刷新到
53    * 主存中去,也可以理解为,就是直接操作主存中的数据,所以在不使用锁的情况下,可以使用volatile。
54    * 这样就可以解决内存可见性的问题了。
55    *
56    * volatile和synchronized的区别
57    *   volatile不具备互斥性(当一个线程持有锁时,其他线程进不来,这就是互斥性)
58    *   volatile不具备原子性。
59    *
60    * */
61    //volatile
62    public volatile boolean flag = false;
63    //原始步骤
64//    public boolean flag = false;
65
66    @Override
67    public void run() {
68        try {
69            Thread.sleep(200);
70        } catch (InterruptedException e) {
71            e.printStackTrace();
72        }
73        flag = true;
74        System.out.println("ThreadDemo线程修改后的flag = " + isFlag());
75    }
76}
77

参考文献:https://www.jianshu.com/p/1f19835e05c0


标题:volatile关键字与内存可见性
作者:zzzzchen
地址:https://dczzs.com/articles/2021/09/02/1630547214988.html