62,632
社区成员




public class VisibilityTest {
Integer a = 0;
public static void main(String[] args) throws InterruptedException {
VisibilityTest test = new VisibilityTest();
test.testVisibility();
}
public void testVisibility() {
new Thread(() -> {
System.out.println("thread 1 start ======= a =" + this.a);
while (this.a != 10) {
}
System.out.println("thred 1 a =======" + this.a);
System.out.println("thread 1 end =======");
}).start();
try {
Thread.sleep(1000L);
// TimeUnit.NANOSECONDS.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
System.out.println("thread 2 modify ....");
this.a = 10;
System.out.println("thread 2 modify success a = " + this.a);
}).start();
}
}
thread 1 start ======= a =0
thread 2 modify ....
thread 2 modify success a = 10
public void testVisibility() {
new Thread(() -> {
System.out.println("thread 1 start ======= a =" + this.a);
while (this.a != 10) {
}
System.out.println("thred 1 a =======" + this.a);
System.out.println("thread 1 end =======");
}).start();
new Thread(() -> {
System.out.println("thread 2 modify ....");
this.a = 10;
System.out.println("thread 2 modify success a = " + this.a);
}).start();
}
thread 1 start ======= a =0
thread 2 modify ....
thread 2 modify success a = 10
thred 1 a =======10
thread 1 end =======
Integer a = 0;
public void testVisibility5() {
Thread t2 = new Thread(() -> {
System.out.println("thread 2 modify ....");
this.a = 10;
System.out.println("thread 2 modify success a = " + this.a);
});
Thread t1 = new Thread(() -> {
int b = this.a;
while (this.a != 10) {
// 值有可能会溢出,暂时不考虑
try {
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("thred 1 a =======" + this.a + " === b =" + b);
System.out.println("thread 1 end =======");
});
t1.start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
加了Thread.sleep()了,线程1也能执行成功了
thread 2 modify ....
thread 2 modify success a = 10
thred 1 a =======10 === b =0
thread 1 end =======
是在同步块里刷新,但是你传给println的参数是0(是刷新前的值),println同步块打印的是传进来的参数,这个参数是线程取得栈变量副本的值传给println方法的,即使println同步块刷新了副本,传进来的参数也不会变。
Integer a = 0;
public void testVisibility5() {
new Thread(() -> {
int b = this.a;
while (this.a != 10) {
}
System.out.println("thred 1 a =======" + this.a + " === b =" + b);
System.out.println("thread 1 end =======");
}).start();
new Thread(() -> {
System.out.println("thread 2 modify ....");
this.a = 10;
System.out.println("thread 2 modify success a = " + this.a);
}).start();
}
输出的结果是:
thread 2 modify ....
thread 2 modify success a = 10
thred 1 a =======10 === b =0
thread 1 end =======
那这个怎么解决了?它没有同步块重新主内存中加载a的值了。在线程1中,b的值就是取a的工作副本的值,但是最后while还是执行成功了,那就说明在while时,工作内存的值被刷新过,但通过目前代码看没有触发的点(就是刷新线程1的工作内存中a变量的值)?是在同步块里刷新,但是你传给println的参数是0(是刷新前的值),println同步块打印的是传进来的参数,这个参数是线程取得栈变量副本的值传给println方法的,即使println同步块刷新了副本,传进来的参数也不会变。
哦!看来我理解错了!难道不是在同步块中就刷新了吗?println是同步块,那么如果刷新的话,应该是在println中就从主内存中获取到了?嗯!基本清楚了,我再了解下同步块的工作内存与主内存变量同步是在什么时候发生的?
[quote=引用 2 楼 generally2008 的回复:] [ 我不是在线程1中有sout输出吗?线程1已经先执行sout,输出thread 1 start ======= a =0, 那线程1的工作内存中存储的就是a = 0 这个副本;所以并不是先执行线程2;如果先执行完线程2,我就没疑问了
public void testVisibility() {
new Thread(() -> {
System.out.println("thread 1 start ======= a =" + this.a);
while (this.a != 10) {
System.out.println("Thread 1 while ==== a ="+this.a); //原因是println是同步方法,会刷新线程的副本
}
System.out.println("thred 1 a =======" + this.a);
System.out.println("thread 1 end =======");
}).start();
new Thread(() -> {
System.out.println("thread 2 modify ....");
this.a = 10;
System.out.println("thread 2 modify success a = " + this.a);
}).start();
}
所以,证明了你之前的有Thread.sleep,就是为了保证线程进入while循环,因为while循环里没有同步方法,所有就不会刷新a,所以一直死循环
[/quote]
哦!看来我理解错了!难道不是在同步块中就刷新了吗?println是同步块,那么如果刷新的话,应该是在println中就从主内存中获取到了?嗯!基本清楚了,我再了解下同步块的工作内存与主内存变量同步是在什么时候发生的?
所以,证明了你之前的有Thread.sleep,就是为了保证线程进入while循环,因为while循环里没有同步方法,所有就不会刷新a,所以一直死循环
public void testVisibility() {
new Thread(() -> {
System.out.println("thread 1 start ======= a =" + this.a);
while (this.a != 10) {
System.out.println("Thread 1 while ==== a ="+this.a); //原因是println是同步方法,会刷新线程的副本
}
System.out.println("thred 1 a =======" + this.a);
System.out.println("thread 1 end =======");
}).start();
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
new Thread(() -> {
System.out.println("thread 2 modify ....");
this.a = 10;
System.out.println("thread 2 modify success a = " + this.a);
}).start();
}
[
我不是在线程1中有sout输出吗?线程1已经先执行sout,输出thread 1 start ======= a =0,
那线程1的工作内存中存储的就是a = 0 这个副本;所以并不是先执行线程2;如果先执行完线程2,我就没疑问了
public void testVisibility() {
new Thread(() -> {
System.out.println("thread 1 start ======= a =" + this.a);
while (this.a != 10) {
System.out.println("Thread 1 while ==== a ="+this.a); //原因是println是同步方法,会刷新线程的副本
}
System.out.println("thred 1 a =======" + this.a);
System.out.println("thread 1 end =======");
}).start();
new Thread(() -> {
System.out.println("thread 2 modify ....");
this.a = 10;
System.out.println("thread 2 modify success a = " + this.a);
}).start();
}
Thread.sleep对变量的可见性没影响,只是影响线程1和线程2的调度而已 如果有Thread.sleep,那线程1会彻底进入while循环,此时应为a是非volatile的,所以线程1的a的值是线程1栈的副本,一直没被刷新,就会死循环。而如果没有Thread.sleep,可能在线程1进入while循环之前可能cpu轮换了,线程2被启动了,先执行了a=10的操作,并刷新了主存,所以cpu再轮换到线程1执行的时候,线程1的a从主存拷贝到自己栈内就是10(最新值),所以没进入while循环,不会导致死循环。