多线程中操作对象的话,该对象的变化对其它线程是不可见的吗?经过测试,答案是否定的。JVM在执行方法时,将方法信息压到方法栈,压入对象时,压的是对象的引用,而非对象的值。
案例一:
多线程,对象传参:
package cn.test.Tread.MethodStackTest;
import lombok.Data;
@Data
public class People {
public String name;
public int age;
People(String name1,int age1){
this.name=name1;
this.age=age1;
}
}
package cn.test.Tread.MethodStackTest;
public class Thread1 extends Thread{
People people;
Thread1(People people1){
this.people = people1;
}
@Override
public void run() {
int i = people.getAge();
try {
Thread.sleep(500);
}catch (InterruptedException e){
}
people.setAge(people.getAge()+1);
while(++i!=people.getAge() && i<10000) {
System.out.println(this.getClass().toString()+"i:"+i+";age:"+people.getAge() );
}
}
}
package cn.test.Tread.MethodStackTest;
import org.springframework.beans.factory.annotation.Autowired;
public class MethodStackTest {
public static boolean b = true;
public static void main(String args[]) {
People people=new People("11",1);
Thread1 thread1 = new Thread1(people);
thread1.start();
while(people.getAge()<10000){
people.setAge(people.getAge()+1);
}
}
}
执行结果:
class cn.test.Tread.MethodStackTest.Thread1i:1058;age:10001
class cn.test.Tread.MethodStackTest.Thread1i:1059;age:10001
class cn.test.Tread.MethodStackTest.Thread1i:1060;age:10001
class cn.test.Tread.MethodStackTest.Thread1i:1061;age:10001
class cn.test.Tread.MethodStackTest.Thread1i:1062;age:10001
class cn.test.Tread.MethodStackTest.Thread1i:1063;age:10001
...
可以看出,多线程入栈后,在外部操作变量对线程内可见。
案例二:
那么,如果操作常量会是什么效果呢?
package cn.test.Tread.MethodStackTest;
public class Thread2 extends Thread {
Boolean b;
Thread2(Boolean b1){
b=b1;
}
@Override
public void run() {
b = false;
}
}
package cn.test.Tread.MethodStackTest;
public class MethodStackInnerClassTest {
public static boolean b =true;
public static void main(String args[]) {
People people = new People("zx", 29);
Thread2 thread2 = new Thread2(b);
thread2.start();
while (b) {
System.out.println("变量未更新");
}
System.out.println("变量已更新");
}
}
此处运行结果,会进入死循环。
可以看出,多线程入栈后,在外部操作常量对线程内不可见。
这是因为变量在方法栈的是【地址】,而常量在方法栈的是【值】。(都是值传递,只是变量传的是地址值)
案例三:
那么,什么情况操作常量,可以对线程间可见呢?有一种场景,就是静态常量。将案例二略微修改一下:
package cn.test.Tread.MethodStackTest;
public class Thread2 extends Thread {
@Override
public void run() {
MethodStackInnerClassTest.b = false;
}
}
package cn.test.Tread.MethodStackTest;
public class MethodStackInnerClassTest {
public static boolean b =true;
public static void main(String args[]) {
People people = new People("zx", 29);
Thread2 thread2 = new Thread2(b);
thread2.start();
while (b) {
System.out.println("变量未更新");
}
System.out.println("变量已更新");
}
}
执行结果:
变量未更新
变量已更新
既然方法栈中存的是变量引用,那么导致多线程可见性的原因是什么呢?
因为缓存。CPU与RAM之间,存在多级缓存,这就导致了缓存数据没有及时更新产生的可见性问题。
参考链接:
java基础之对象当做参数传进方法的堆栈内存解析 - 青衫仗剑 - 博客园https://www.cnblogs.com/blazezzz/p/9103575.htmlJava多线程 可见性问题出现的原因_Java持续实践-CSDN博客_java多线程可见性问题文章目录可见性问题出现的原因可见性问题出现的原因主要的原因可以从下图中分析出来.此图中, 最下层为ram, 也就是内存, 而内存离CPU之间 ,是有多级的缓存的.L3 cache为内存的一部分, 会把内存中高频用到的部分缓存起来.L2 cache为L3 cache的一部分, 会把L3 cache高频用到的部分缓存起来.L1 cache为L2 cache的一部分, 会把L2 cache高频用到的部分缓存起来.每一层缓存的大小在缩小, 但读取速度在不断的增加.到了Register 是寄存器,https://blog.csdn.net/qq_33229669/article/details/108421939
|