lcok-free简易实现

lock-free是一种基于原子变量类来构建的非阻塞同步算法。

比较并交换(compare-and-swap)

我们经常会先检查某项东西,然后对其进行修改,如if(X...) {X=...}。这种行为在多线程下并不是线程安全的。那我们该如何做呢?

一种方法是对操作进行加锁,如

synchornized(obj){

    if(x>0){

        x -=  10; 

    }

}

究其原因,是因为上面的操作是一个复合操作。我们是否可以通过某种不可分的方式来处理呢?...

几乎所有的现代处理器都包含了比较并交换(CAS)指令。CAS包含了3个操作数--需要读写内存的位置V、进行比较的值A和拟写入的新值,当且仅当V的值等于A时,CAS才会通过原子的方式用新值B来更新V的值,否则不会执行任何操作。通过CAS我们可以把这种“先检查后执行”行为作为一个不可分的整体来处理。在Java1.5之后,原子变量类中提供了这种操作。

下面写个简单取钱的例子,看看其在Java下的应用。账户有一定的余额(10000),在多线程下每个人一次可取4000。如果写的withDraw(long)线程不安全,则可能余额被减成负数。

public class AccountCAS extends Thread{
    private Account account;
    public AccountCAS(Account account){
        super();
        this.account = account;
    }
    
    @Override
    public void run() {
        
        try {
            Thread.sleep(500);
            account.withDraw(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        final int NUM = 5;
        Account ac = new Account();
        for(int i=0;i<NUM;++i){
            new AccountCAS(ac).start();
        }
    }

}

class Account{
    /**
     * 余额
     */
    private AtomicLong balance = new AtomicLong(10000);
    
    public void withDraw(long money){
        long oldValue = balance.get();
        if(oldValue>=money){
            while(true){
                if(balance.compareAndSet(oldValue, oldValue-money)){
                    System.out.println(Thread.currentThread().getName()+" withDraw:"+money);
                    break;
                }
            }
        }
    }
}

运行结果如下:

Thread-0 withDraw:4000

Thread-3 withDraw:4000

以上的Lock-free算法不需要加锁,通常包含以下几点:1.原子变量 2.循环 3.CAS 4.退出

原文地址:https://www.cnblogs.com/dreamysmurf/p/4009110.html