Java 提供了一种稍弱的同步机制,即 volatile 变量,用来确保将变量的更新操作通知到其他线程。 可以将 volatile 看做一个轻量级的锁,但是又与 锁有些不同:
我们先看代码
package com.gf.demo;
public class TestVolatile {
public static void main(String args[]){
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while (true) {
if (td.isFlag()) {
System.out.println("----------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep( 200 );
flag = true;
System.out.println( flag );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
你会发现一个问题 : main线程一直运行,新建立的 Thread 和 main线程 共享 td 对象 ,为什么 main线程 不打印虚线呢 ?
如图所示,线程1 和 main线程在访问 flag 是都是主存中复制一份到自己的本地,然后操作 ,线程1 修改 flag = true,同步到主存中,虽然主存中的flag 变成了true,然是由于main线程中的while(true) 调用的是计算机比较底层的方法,所以,执行效率非常高 ,跟没有机会与主存中的数据同步。也就是说多线程操作共享数据时,彼此不可见。
package com.gf.demo;
public class TestVolatile {
public static void main(String args[]){
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while (true) {
synchronized(td){
if (td.isFlag()) {
System.out.println("----------------");
break;
}
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep( 200 );
flag = true;
System.out.println( flag );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
加了synchronized 解决了问题,但是加锁 ,就必然有锁竞争,效率低下。
package com.gf.demo;
/**
* 一、volatile 关键字:当多个线程进行操作共享数据时,可以保证线程间共享数据的可见性。
* 相比与synchronized 是一种较为轻量级的同步策略。
*
* 注意:
* 1. volatile 不具备 "互斥性"
* 2. volatile 不能保证变量的原子性
*/
public class TestVolatile {
public static void main(String args[]){
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while (true) {
if (td.isFlag()) {
System.out.println("----------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private volatile boolean flag = false;
@Override
public void run() {
try {
Thread.sleep( 200 );
flag = true;
System.out.println( flag );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
通过上面的例子我们可以得出下面的结论:
评论