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