目录
一、什么是线程的可见性 二、可见性问题示例
三、解决可见性问题 3.1 volatile关键字 3.2 synchronized关键字
四、用volatile关键字解决可见性问题示例
五、用synchronized关键字解决可见性问题示例
六、可见性与原子性
一、什么是线程的可见性
1.当一个线程修改了共享变量的值,其他线程会马上知道这个修改。当其他线程要读取这个变量的时候,最终会去内存中读取,而不是从缓存中读取 2.一个线程对共享变量的修改,另一个线程可以感知到,称为可见性 3.在CPU中存在MESI协议,即缓存的一致性协议:一个线程修改变量,CPU会刷新缓存,并刷新回内存,线程2得知线程1修改变量,cpu2通过总线嗅探机制,会重新去内存中加载变量a
二、可见性问题示例
2.1 代码
package com.learning.visibility;
/**
* @Description 可见性学习
*/
public class VisibilityLearning {
static boolean run = true;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while(run){
System.out.println("thread没有停止");
}
});
thread.start();
Thread.sleep(1000);
System.out.println("主线程停止thread");
run = false;
}
}
2.2 截图
三、解决可见性问题
3.1 volatile关键字
1.使用volatile [ˈvɑːlətl]关键字修饰变量 2.volatile 易变关键字 3.可以用来修饰成员变量和静态成员变量 4.可以避免线程从自己的工作缓存中查找变量的值,必须从主存中获取变量的值,线程操作volatile变量都是直接操作主存
3.2 synchronized关键字
1.synchronized关键字会清空工作内存,代码块结束后将更改后的共享变量的值刷新到主内存中
四、用volatile关键字解决可见性问题示例
4.1 代码
package com.learning.visibility;
/**
* @Description 可见性学习
*/
public class VisibilityLearning {
volatile static boolean run = true;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while(run){
System.out.println("thread没有停止");
}
});
thread.start();
Thread.sleep(1000);
System.out.println("主线程停止thread");
run = false;
}
}
4.2 截图
五、用synchronized关键字解决可见性问题示例
5.1 代码
package com.learning.visibility;
/**
* @Description 可见性学习
*/
public class VisibilityLearning {
static boolean run = true;
//锁对象
final static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while(true){
synchronized (lock){
System.out.println("thread没有停止");
if(!run){
break;
}
}
}
});
thread.start();
Thread.sleep(1000);
System.out.println("主线程停止thread");
synchronized (lock){
run = false;
}
}
}
5.2 截图
六、可见性与原子性
1.一个线程对volatile变量的修改对另一个线程可见,不能保证原子性,仅用在一个写线程,多个读线程的情况 2.volatile只能保证看到最新值,不能解决指令交错 3.synchronized语句块既可以保证代码块的原子性,也同时保证代码块内变量的可见性,缺点是synchronized是属于重量级的操作,性能相对更低