在java中,设计之初就有了:主内存、线程工作内存,所以其实每一个线程执行时,都是将主线程copy一份到工作线程,执行修改后,再同步回去。
所以,就有四组内存操作方式:
1、读主内存,加载到工作内存
2、 通过执行引擎使用工作内存数据、修改工作内存
3、读工作内存、写到主内存
4、使用内存时会:加锁,解锁
volatile可以让多个线程可见,或者说不再操作工作内存
package com.quxiao.controller; import java.sql.Time; import java.util.ArrayList; import java.util.Random; import java.util.concurrent.*; import java.util.stream.LongStream; /** * @program: package1 * @author: quxiao * @create: 2023-09-27 15:22 **/ public class t3 { static volatile int sum = 0; public static void main(String[] args) throws InterruptedException { new Thread(() -> { while (sum == 0) { } System.out.println(1); }).start(); TimeUnit.SECONDS.sleep(1); sum = 1; } }
但是使用了volatile就没有了原子性,也就是线程操作不再唯一,例如:
A线程取出时为10,正准备+10,数据变成了15,结果就成了15+10。
指令重排(很神奇的一个东西):
package com.quxiao.controller; import java.sql.Time; import java.util.ArrayList; import java.util.Random; import java.util.concurrent.*; import java.util.stream.LongStream; /** * @program: package1 * @author: quxiao * @create: 2023-09-27 15:22 **/ public class t3 { static int x = 0; static int y = 0; static int a = 0; static int b = 0; public static void main(String[] args) throws InterruptedException { //大致如此,但是 new Thread(() -> { x = a; b = 1; }).start(); new Thread(() -> { y = b; a = 2; }).start(); //有可能x=2,y=1 System.out.println(x + ":" + y); } }
x=b和a=1这两句话完全没有关联,编译器就有可能把他俩重新排顺序。(上面的代码只是理论,其实很难遇到)
加上volatile,就能解决,多了两层内存屏障: