8、线程同步机制(volatile与CAS)

2019-04-23  本文已影响0人  小manong

一、轻量级同步机制:valotile关键字

1、作用
2、开销
3、应用场景

(1)使用volatile变量作为状态标志

应用程序的某一个状态由一个线程设置,其他线程会读取到该状态并以该状态作为计算的依据。使用volatile变量的好处是在多线程环境中,volatile作为同步机制能够及时通知另外一个线程某种事件的发生(网络异常等),而这些线程无需使用锁,从而保证了锁的开销以及相关问题。

(2)使用volatile代替锁

要使用volatile实现锁的原子性,可以把这一组状态变量封装为一个对象,那么对这些状态变量的操作就可以通过创建一个新的对象并将该对象引用赋值给相应的引用性变量来实现。利用了volatile的可见性和有序性。(锁适用于共享一个状态变量或者对象,volatile变量适用于共享一组状态变量,这组状态变量可以封装为一个对象)

(3)使用volatile关键字实现简易的读写锁

这个场合混合使用了锁和volatile关键字,锁用于保证对共享数据操作的原子性,volatile对于共享数据读取的可见性和有序性保证。

 private volatile long count;

    public long readCount() {
        return count;
    }

    public void writeCount() {
        synchronized (LockTest.class) {
            count++;
        }
    }
5、使用案例分析

1、需要支持多种负载均衡算法,如随机算法、轮询算法、加权轮询算法等。
2、需要支持在系统运行中动态的调整负载均衡算法
3、需要在线剔除无用的机器
4、下游部件的节点信息可以动态调整(删除、添加等)

6、volatile在单例模式下面的使用
public class SingletonByDoubleLock {
    /**
     * 使用volatile修饰保证有序性和可见性
     */
    private static volatile SingletonByDoubleLock instance = null;

    private SingletonByDoubleLock() {
    }

    public static SingletonByDoubleLock newInstance() {
        if (instance == null) {//1、第一次检验
            synchronized (SingletonByDoubleLock.class) {
                if (instance == null) {//2、第二次检验
                    return new SingletonByDoubleLock();//3、操作3可能发生重排序
                }
            }
        }
        return instance;
    }

}

public class SingletonByStaticClass {
  
    private SingletonByStaticClass() {

    }
    /**
     * 静态内部试验的单例
     */
    private static class StaticInnerClass {
        private final static SingletonByStaticClass SINGLETON = new SingletonByStaticClass();
    }

    public static SingletonByStaticClass newInstance() {
        return StaticInnerClass.SINGLETON;
    }
}
public enum SingletonEnum {
    INSTANCE;

    SingletonEnum() {
    }

    public void doSomeThing() {

    }
}

二、CAS与原子变量

1、CAS介绍
boolean compareAndSwap(Variable V,Object A,Object B){
        //check:检查变量是否被其他线程修改过
        if (A==V.get()){
            //act:更新变量,更新成功
            V.set(B);
            return true;
        }
        //变量值已经被其他的线程修改过,更新失败
        return false;
    }
public class CASAtomicCounter {
   public class CASAtomicCounter {
    /**
     * 使用volatile保证可见性,cas只保证原子性
     */
    private volatile long count;
    /**
     * 这里使用AtomicLongFieldUpdater只是为了便于讲解和运行该实例,
     * 实际上更多的情况是我们不使用AtomicLongFieldUpdater,而是使用
     * java.util.concurrent.atomic包下的其他更为直接的类。
     */
    private final AtomicLongFieldUpdater<CASAtomicCounter> fieldUpdater;

    public CASAtomicCounter() {
        fieldUpdater = AtomicLongFieldUpdater.newUpdater(CASAtomicCounter.class,
                "count");
    }

    public long getCount() {
        return count;
    }

    public void increment() {
        long oldValue;
        long newValue;
        do {
            //读取共享变量的当前值(旧值)
            oldValue = count;
            //计算共享变量的新值(新值)
            newValue = oldValue + 1;
            //CAS更新共享变量的值,循环用于更新失败的时候继续重试
        } while (!compareAndSwap(oldValue, newValue));
    }

    /*
     * 该方法是个实例方法,且共享变量count是当前类的实例变量,因此这里我们没有
必要在方法参数中声明一个表示共享变量的参数,最终底层是使用c语言实现(指令层面保证了)
     */
    private boolean compareAndSwap(long oldValue, long newValue) {
        boolean isOK = fieldUpdater.compareAndSet(this, oldValue, newValue);
        return isOK;
    }
2、原子操作工具:原子变量类
//指标统计器
public class Indicator {
    /**
     * 唯一实例
     */
    private static final Indicator INSTANCE = new Indicator();
    /**
     * 总请求数量
     */
    private final AtomicLong requestCount = new AtomicLong();
    /**
     * 成功数量
     */
    private final AtomicLong successCount = new AtomicLong();
    /**
     * 请求失败数量
     */
    private final AtomicLong failCount = new AtomicLong();

    private Indicator() {
    }

    public void newRequestRecieved() {
        //总请求加1
        requestCount.incrementAndGet();
    }

    public void requestProcessSuccess() {
        successCount.incrementAndGet();
    }

    public void requestProcessfail() {
        failCount.incrementAndGet();
    }

    public long getRequestCount() {
        return requestCount.get();
    }

    public long getSuccessCount() {
        return successCount.get();
    }

    public long getFailCount() {
        return failCount.get();
    }

    public void reset() {
        requestCount.set(0);
        successCount.set(0);
        failCount.set(0);
    }
}

3、ABA问题及解决

三、static和final关键字

1、static关键字
2、final关键字

四、总结

线程同步机制总结
上一篇下一篇

猜你喜欢

热点阅读