Java并发程序设计(七)乐天派:无锁

无锁

一、概述

无锁是处理并发的一种乐观策略,它会假设对资源的访问是没有冲突的。既然没有冲突自然不需要等待,所以所有的线程都可以在不停顿的状态下执行。那遇到冲突怎么办?接下来请看,无锁绝招“CAS”即比较交换术。

二、CAS原理

CAS即Compare and swap.其算法过程是这样的:它有三个参数:

1.V表示要更新的变量

2.E表示期望值

3.N表示新值

仅当V等于E时,才会将V设为N。如果V和N不同,则说明有其他线程做了更新,则该线程什么都不做。当多个线程同时使用CAS进行变量操作时,只有一个会更新成功,其余都会失败。失败的线程不会被挂起,而是进行重试。

 

三、无锁的线程安全整数:AtomicInteger

AtomicInteger主要方法如下(对于其他无锁线程安全类,其方法类似):

public final int get() //取得当前值
public final void set(int newValue) //设置当前值
public final int getAndset(int newValue) //设置新值返回旧值
public final boolean compareAndSet(int except,int u) //如果当前值为except则设为u
public final int getAndIncrement() //当前值加1返回旧值
public final int getAndDecrement() 
public final int getAndAdd(int delta)
public final int incrementAndGet()
public final int decrementAndGet()
public final int addAndGet() 

就AtomicInteger核心字段:

private volatile int value; //代表AtomicInteger当前的值
private static final long valueOffset; //value字段的偏移量

AtomicInteger的使用示例:

public class AutomicIntegerDemo {

    static AtomicInteger i=new AtomicInteger();

    public static class addThread implements Runnable{

        @Override
        public void run() {
            for(int j=0;j<1000;j++){
                i.incrementAndGet();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread[] ts=new Thread[10];
        for(int j=0;j<10;j++){
            ts[j]=new Thread(new addThread());
        }

        for(int j=0;j<10;j++) ts[j].start();
        for (int j=0;j<10;j++) ts[j].join();

        System.out.println(i);
    }
}

相比使用锁,使用无锁会有更好的性能。

 

四、CAS算法逻辑上瑕疵及解决办法:AtomicStampedReference

CAS算法逻辑上的瑕疵:当你获得对象当前数据后,在准备修改为新值前,对象的值被其他对象连续修改了两次,而经过这两次修改后,对象的值又恢复到旧值。这样,当前线程就无法判断该值是否被修改过。也就是说你修改的对象数值没有过程状态信息。

AtomicStampedReference内部不仅维护了对象值还维护了一个状态值。

 

五、无锁数组

当前可用的原子数组有:AtomicIntegerArray,AtomicLongArray和AtomicReferenceArray

public class AtomicIntegerArrayDemo {

    static AtomicIntegerArray array=new AtomicIntegerArray(10);

    public static class addThread implements Runnable{

        @Override
        public void run() {
            for (int j=0;j<1000;j++){
                array.getAndIncrement(j%array.length());
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread[] ts=new Thread[10];
        for (int j=0;j<10;j++){
            ts[j]=new Thread(new addThread());
        }

        for (int j=0;j<10;j++) ts[j].start();

        for (int j=0;j<10;j++) ts[j].join();

        System.out.println(array);
    }
}

 

六、让普通变量也享受原子操作:AtomicIntegerFieldUpdater

public class AtomicIntegerFieldUpdaterDemon {

    public static class Candidate{
        int id;
        volatile int score;
    }

    public final static AtomicIntegerFieldUpdater<Candidate> scoreUpdater=
            AtomicIntegerFieldUpdater.newUpdater(Candidate.class,"score");

    public static AtomicInteger checkScore=new AtomicInteger(0); //用于检测

    public static void main(String[] args) throws InterruptedException {
        final Candidate candidate=new Candidate();
        Thread[] threads=new Thread[1000];
        for (int i=0;i<1000;i++){
            threads[i]=new Thread(){
                public void run(){
                    if (Math.random()>0.4){
                        scoreUpdater.incrementAndGet(candidate);
                        checkScore.incrementAndGet();
                    }
                }
            };
            threads[i].start();
        }

        for (int i=0;i<1000;i++) threads[i].join();
        System.out.println("score="+candidate.score);
        System.out.println("checkScore="+checkScore);
    }
}

注意事项:

1.Updater只能修改可见范围内的变量。

2.变量必须是volatile

3.变量不能是static的

 

posted @ 2017-09-06 14:00  Shadowplay  阅读(184)  评论(0编辑  收藏  举报