package com.zxy.demo.thread;
import lombok.Data;
/**
* @author ZhangXiaoYu
* @date 2021/9/2 9:26
*/
public class ThreadDemo1 {
//volatile关键字与内存可见性
/*
* new一个线程子类实例并start,线程内部睡眠200毫秒后将flag设置为true
* 主线程使用while循环,如果线程子类的成员变量flag为true时,输出一句话后break出循环。
* 问题1:在主线程while循环时,flag已经为true,却没有跳出循环,为什么?
* 这是内存可见性的问题。当多个线程操作共享数据时,彼此不可见。
* 基本可以理解为,ThreadDemo线程先从主存中把数据读取过来,读取到的是false,然后修改为true,就在还未来得及把true同步到主存
* 时,main进来了,这是main读取到的还是false,所以形成死循环,就在main循环时,ThreadDemo线程把true同步到主存了,所以
* ThreadDemo线程中输出语句打印的是true。
*
* 要解决这个问题,可以加锁。
* */
public static void main(String[] args) throws InterruptedException { //这个线程是用来读取flag的值的
ThreadDemo threadDemo = new ThreadDemo();
Thread thread = new Thread(threadDemo);
thread.start();
//加锁处理
/*
* 加了锁,就可以让while循环每次都从主存中去读取数据,这样就能读取到true了,但是一旦加了锁,每次只能有一个线程访问,
* 当一个线程持有锁时,其他的就会阻塞,效率就非常低了,不想加锁,又要解决内存可见性问题,那么就可以使用volatile关键字。
* */
// while (true) {
// synchronized (threadDemo){
// if (threadDemo.isFlag()) {
// System.out.println("主线程读取到的flag = " + threadDemo.isFlag());
// break;
// }
// }
// }
//原始步骤
while (true) {
if (threadDemo.isFlag()) {
System.out.println("主线程读取到的flag = " + threadDemo.isFlag());
break;
}
}
}
}
@Data
class ThreadDemo implements Runnable { //这个线程是用来修改flag的值的
/*
* volatile关键字:当多个线程操作共享数据时,可以保证内存中的数据可见,用这个关键字修饰共享数据,就会及时的把线程缓存中的数据刷新到
* 主存中去,也可以理解为,就是直接操作主存中的数据,所以在不使用锁的情况下,可以使用volatile。
* 这样就可以解决内存可见性的问题了。
*
* volatile和synchronized的区别
* volatile不具备互斥性(当一个线程持有锁时,其他线程进不来,这就是互斥性)
* volatile不具备原子性。
*
* */
//volatile
public volatile boolean flag = false;
//原始步骤
// public boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("ThreadDemo线程修改后的flag = " + isFlag());
}
}
参考文献:https://www.jianshu.com/p/1f19835e05c0