`

volatile

阅读更多
正确使用volatile

在jdk5修正了volatile的语义后,volatile作为一种轻量级的同步策略就得到了大量的使用。volatile的严格定义参考jvm spec,这里只从volatile能做什么,和不能用来做什么出发做个探讨。

volatile可以用来做什么?

1)状态标志,模拟控制机制。常见用途如控制线程是否停止:

private volatile boolean stopped; 
public void close(){ 
   stopped=true; 


public void run(){ 

   while(!stopped){ 
      //do something 
   } 
    
}
前提是do something中不会有阻塞调用之类。volatile保证stopped变量的可见性,run方法中读取stopped变量总是main memory中的最新值。

2)安全发布,如修复DLC问题。

private volatile IoBufferAllocator instance; 
public IoBufferAllocator getInsntace(){ 
    if(instance==null){ 
        synchronized (IoBufferAllocator.class) { 
            if(instance==null) 
                instance=new IoBufferAllocator(); 
        } 
    } 
    return instance; 
}
3)开销较低的读写锁

public class CheesyCounter { 
    private volatile int value; 

    public int getValue() { return value; } 

    public synchronized int increment() { 
        return value++; 
    } 

synchronized保证更新的原子性,volatile保证线程间的可见性。

volatile不能用于做什么?

1)不能用于做计数器

public class CheesyCounter { 
    private volatile int value; 

    public int getValue() { return value; } 

    public int increment() { 
        return value++; 
    } 
}
因为value++其实是有三个操作组成的:读取、修改、写入,volatile不能保证这个序列是原子的。对value的修改操作依赖于value的最新值。解决这个问题的方法可以将increment方法同步,或者使用AtomicInteger原子类。

2)与其他变量构成不变式

一个典型的例子是定义一个数据范围,需要保证约束lower< upper。

public class NumberRange { 
    private volatile int lower, upper; 

    public int getLower() { return lower; } 
    public int getUpper() { return upper; } 

    public void setLower(int value) {  
        if (value > upper)  
            throw new IllegalArgumentException(); 
        lower = value; 
    } 

    public void setUpper(int value) {  
        if (value < lower)  
            throw new IllegalArgumentException(); 
        upper = value; 
    } 

尽管讲lower和upper声明为volatile,但是setLower和setUpper并不是线程安全方法。假设初始状态为(0,5),同时调用setLower(4)和setUpper(3),两个线程交叉进行,最后结果可能是(4,3),违反了约束条件。修改这个问题的办法就是将setLower和setUpper同步:

public class NumberRange { 
    private volatile int lower, upper; 

    public int getLower() { return lower; } 
    public int getUpper() { return upper; } 

    public synchronized void setLower(int value) {  
        if (value > upper)  
            throw new IllegalArgumentException(); 
        lower = value; 
    } 

    public synchronized void setUpper(int value) {  
        if (value < lower)  
            throw new IllegalArgumentException(); 
        upper = value; 
    } 
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics