- Java语言允许线程访问共享变量,为了确保一致和可靠地更新共享变量,一个线程应该通过一个获取一个锁来确保它独占使用变量.一般来说,可以通过互斥来实现.
Java语言提供了第二个机制----volatile关键字, 他比锁更简单.被声明为volatile的变量,可以保证所有的线程可以一致的访问这个变量.
- volatile提供了稍弱的同步机制,用来确保将变量的更新操作通知到其他线程.当变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将改变量上的操作与其他内存操作一起重排序.volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此读取volatile类型的变量时总会返回最新写入的值.
- 总之,一句话, volatile保证共享变量值改变后,能被其他所有的线程看到
一,不使用任何措施的示例
public class VolatitleTest {
public static void main(String[] args) {
OneThread one = new OneThread();
TwoThread two = new TwoThread();
one.start();
two.start();
}
static int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
static class OneThread extends Thread{
public void run(){
for(;;){
VolatitleTest.one();
}
}
}
static class TwoThread extends Thread{
public void run(){
for(;;){
VolatitleTest.two();
}
}
}
}
将会出现方法two()打印的j的值大于i的值. 出现的原因就是当线程1对i和j进行自增后, i更新的值不能被线程2看到.
二,使用synchronzied关键字
static int i = 0, j = 0;
static synchronized void one() { i++; j++; }
static synchronized void two() {
System.out.println("i=" + i + " j=" + j);
}
使用synchronzied关键字后,方法one()和方法two()不能并发的执行,从而保证了共享变量i和j在方法one()结束后都被更新.
三,使用volatile关键字
static volatitle int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
- 当使用volatile修饰变量i,j的时候, 当i和j的值改变的时候, 线程立马的就可以看到改变后的值.
- 但是当使用volatile之后,还会出现j比i大的情况,但是此时并不是因为i的值更改后不能被其他线程看见, 是因为多个线程同时操纵i和j造成的.
与第二示例使用synchronized相比, synchronized的加锁机制可以确保可见性和原子性,而volatile仅仅可以确保可见性
参考:
<<java编发编程实战>>
网友评论