Java 内存模型和线程的三大特性
多线程有三大特性: 原子性, 可见性, 有序性
1,Java 内存模型
Java 内存模型 (Java Memory Model ,JMM), 决定一个线程对共享变量的写入时, 能对另一个线程可见. 从抽象的角度来看, JMM 定义了线程和主内存之间的抽象关系: 线程之间的共享变量存储在主内存(main memory) 中, 每个线程都有一个私有的本地内存(local memory), 本地内存中存储了该线程以读 / 写共享变量的副本. 本地内存是 JMM 的一个抽象概念, 并不真实存在.
用一张图表示 Java 内存模型
2, 原子性
原子性即一个操作或多个操作, 要么全部执行并且执行过程不被任何因素打断, 要么就都不执行.
一个经典的例子就是数据库存储的事务. 原子性其实就是保证数据一致, 线程安全的一部分.
Synchronized,lock 可以解决线程原子性问题
3, 可见性
当多个线程访问同一个变量时, 一个线程修改了这个变量的值, 其他线程能够立即看得到修改的值.
若两个线程在不同的 CPU, 那么线程 1 改变了 i 的值还没刷新到主存, 线程 2 又使用了 i, 那么这个 i 值肯定还是之前的, 线程 1 对变量的修改其他线程没看到, 这就是可见性问题.
Volatile 可以解决线程可见性问题
4, 有序性
程序执行的顺序按照代码的先后顺序执行.
一般来说处理器为了提高程序运行效率, 可能会对输入代码进行优化, 它不保证程序中各个语句的执行先后顺序同代码中的顺序一致, 但是它会保证程序最终执行结果和代码顺序执行的结果是一致的.
而在多线程就不一定了, 所以我们在多线程编程时就得考虑这个问题了.
5,volatile 关键字可以解决线程之间可见性的问题
- class ThreadDemo extends Thread {
- boolean flag;
- ThreadDemo(boolean flag) {
- this.flag = flag;
- }
- @Override
- public void run() {
- System.out.println(getName() + "线程开始运行...");
- while (flag) {
- }
- System.out.println(getName() + "线程已经结束...");
- }
- public void stopThread() {
- this.flag = false;
- }
- }
- public class VolatileThreadDemo {
- public static void main(String[] args) {
- ThreadDemo threadDemo = new ThreadDemo(true);
- threadDemo.start();
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- threadDemo.stopThread();
- }
- }
先来看以上的代码, 在主线程中调用 threadDemo.stopThread()方法停止线程, 看上去逻辑没有问题, 但是我们会发现线程没有停止.
注意: 有的同学可能在测试上面代码的时候程序可以正常退出. 那是因为你的 JVM 没有优化造成的!
造成线程没有停止的原因是 while(flag)中的 flag 是在线程运行的 "工作内存" 中获取的, 而不是从 "主内存" 中获取的, 这就造成了我们在主线程中改变 flag 的值对于子线程中不生效. 只要在 flag 前加 volatile 关键字, 强制线程每次读取该值的时候都去 "主内存" 中取值, 就能解决我们的问题.
- package com.littlestones.volatiledemo;
- /**
- * @program: JavaThreadLearn
- * @description: volatile 示例
- * @author: Leil
- * @create: 2019-12-24 15:22
- */
- class ThreadDemo extends Thread {
- volatile boolean flag;
- ThreadDemo(boolean flag) {
- this.flag = flag;
- }
- @Override
- public void run() {
- System.out.println(getName() + "线程开始运行...");
- while (flag) {
- }
- System.out.println(getName() + "线程已经结束...");
- }
- public void stopThread() {
- this.flag = false;
- }
- }
- public class VolatileThreadDemo {
- public static void main(String[] args) {
- ThreadDemo threadDemo = new ThreadDemo(true);
- threadDemo.start();
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- threadDemo.stopThread();
- }
- }
注意: volatile 关键字只能解决线程的可见性问题, 不能解决线程的原子性问题
来源: https://www.cnblogs.com/3LittleStones/p/12096808.html