在研究Java并发, 内存模型时, 遇到了一些问题?
public class VolatileDemo {
final static int MAX = 5;
static int initVal = 0;
static volatile int b=0;
public static void main(String[] args) {
new Thread(() -> {
int localVal = initVal;
while (localVal < MAX) {
if (initVal != localVal) {
b++;
System.out.printf("The iniVal is updated to [%d]\n", initVal);// A步骤
localVal = initVal;
}
}
}, "Reader").start();
new Thread(() -> {
int localVal = initVal;
while (localVal < MAX) {
System.out.printf("The initVal will be cahnged to [%d]\n", ++localVal);
initVal = localVal;
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Updater").start();
}
}
以上的代码中, A 步骤永远不会发生(我测试了很多次, 我知道如果给变量加了volatile之后可以解决这个问题)。为什么?
public class UnsafeThread implements Runnable {
private static int count = 0;
public void increase(){
count++;
}
public void run() {
for (int i = 0; i < 1000000000; i++) {
increase();
}
}
public static void main(String[] args) {
UnsafeThread myThread = new UnsafeThread();
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
System.out.println(count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
感谢你能阅读到这, 如果知道答案, 望解惑一二, 谢谢
看看这个,对你帮助应该很大
https://www.cnblogs.com/dolphin0520/p/3920373.html
你的A条件哪里第一次都不能进去,永远都不满足条件,怎么执行?
个人见解。应该知道变量没加volatile时,jvm会通知调用该变量的线程同步该变量的值到工作内存中,这个是实时性的。如果不加,线程就会直接使用存储在工作内存中的变量。
代码执行的速度是迅速的,而没有使用volatile时,当第二个线程改变了变量时 initVal = localVal,这个需要先同步到主内存中,主内存还来不及将变量同步到第一个线程中。第一个线程已经结束了。还有就是你在第二个线程中的等待时间,变量的值早就同步好了。所以才会不要低估代码的运行速度。
你的第二个demo,如果是一直访问主内存中值,那结果应该是2000000000,小的原因就是访问的是工作内存中的值。
多线程2大特性,1:原子性,2:可见性,
原子性:我们对数据的操作或者业务的操作要符合独立原则,也就是每一个业务就是一个最小单位,这样就不会发生数据超出或者重复的问题,
可见性:我们对变量的操作,或者说对象的操作,如果有多个线程公用这一个变量,则必须保证可见性,因为jvm在使用变量的时候,会从堆栈空间将变量移入交换区
,如果不保证可见性,呢么就会出现a线程更改了变量的值,但是这时候jvm
还没有来得及刷新交换区
将其值写入堆栈空间,这时候b线程来了,拿的还是原来的值,就会发生问题,所以,要保证可见性,其就可以保证在交换区的值,对b线程可见,呢么,b线程就可以拿到交换区的值,这就是你为什么加volititle
就可以的原因