目录
- 一、什么是线程的可见性
- 二、可见性问题示例
-
- 三、解决可见性问题
- 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是属于重量级的操作,性能相对更低