Volatile、Static、Synchronized的可见性
2018-06-25 本文已影响0人
冰鱼飞鸟
1.Static并不能保证在各个线程中值的一致,因为每个线程有自己的工作内存,工作内存中的变量值是主内存中的拷贝,没有重新从主内存中加载时,并不能知道别的线程对这个变量做了什么修改。
public static boolean isRun = true;
public static void main(String[] args) throws InterruptedException {
Thread1 t1 = new Thread1(1);
t1.start();
Thread.sleep(1000);
isRun = false;
System.err.println("--------stop");;
}
static class Thread1 extends Thread{
private int flag;
public Thread1(int flag) {
this.flag = flag;
}
@Override
public void run() {
super.run();
while(true) {
if(!isRun) {
System.err.println(flag+"," + isRun);
break;
}
}
}
}
结果如下
--------stop
结果是stop已经打印出来,线程中的循环结束不了,因为线程的工作内存中的isRun值还是true,并没有重新从主内存中获取修改后的值。
2.Volatile,java内存模型保证volatile修饰的变量在各个线程中保持一致,即可见性保证。当一个线程修改了该变量的值,修改后的值可以立即被其他线程获取到。
(ps:普通变量的值如果要在线程间传递要通过主内存做过渡,及A线程要把修改后的值同步回主内存,B线程要从主内存中获取才能获得普通变量的新值。)
(ps: Volatile保证可见性,并不能保证对volatile的所有操作都是线程安全,这还要考虑操作的原子性,如volatile int i; i++;并不是原子操作,靠volatile不能保证其线程安全。)
将上面例子中的isRun加上volatile修饰。
public static volatile boolean isRun = true;
// public static boolean isRun = true;
public static void main(String[] args) throws InterruptedException {
Thread1 t1 = new Thread1(1);
t1.start();
Thread.sleep(1000);
isRun = false;
System.err.println("--------stop");;
}
static class Thread1 extends Thread{
private int flag;
public Thread1(int flag) {
this.flag = flag;
}
@Override
public void run() {
super.run();
while(true) {
if(!isRun) {
System.err.println(flag+"," + isRun);
break;
}
}
}
}
结果如下
--------stop
1,false
3.Synchronized 在保证互斥的同时,还可以保证可见。在进入同步代码块时会使当前线程的工作内存失效,强制从主内存重新获取。
所以如第一个例子在线程中加上synchronized代码块时
public static boolean isRun = true;
public static void main(String[] args) throws InterruptedException {
Thread1 t1 = new Thread1(1);
t1.start();
Thread.sleep(1000);
isRun = false;
System.err.println("--------stop");;
}
static class Thread1 extends Thread{
private int flag;
public Thread1(int flag) {
this.flag = flag;
}
@Override
public void run() {
super.run();
while(true) {
if(!isRun) {
System.err.println(flag+"," + isRun);
break;
}
//System.err.println("thread is running.");
synchronized ("") {
}
}
}
}
结果如下
--------stop
1,false
另外一点在测试中发现的是,其实在线程中System.....print和加同步代码块是一样的效果。看System....print的源码,其实就是synchronized。
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}