悲观锁synchronized、乐观锁CAS

1、悲观锁

乐观锁、悲观锁是一种思想

  • 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。
  • 一个线程持有锁会导致其它所有需要此锁的线程挂起。
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。

      synchronized属于悲观锁,JDK1.5之前都是靠synchronized关键字保证同步的,可以确保无论哪个线程持有共享变量的锁,都采用独占的方式来访问这些变量,独占锁其实就是一种悲观锁。

引用:https://blog.csdn.net/caisongcheng_good/article/details/79916873

2、乐观锁

       相对悲观锁而言,乐观锁主要就是两个步骤:冲突检测和数据更新。假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。   

      CAS(Compare and Swap)属于乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS是一种非阻塞式的同步方式。

     CAS算法过程:CAS(V,E,N)它有三个操作数分别为:V表示要更新的变量,E表示预估值,N表示新值。当且仅当V值等于E值时,才将V的值设置为N;如果V值和E值不同, 返回当前V的值。

    CAS算法(JAVA实现)

public class AtomicInteger extends Number implements java.io.Serializable {
    
    //利用volatile关键字,保证线程间的数据是可见的(共享的),这样才获取变量的值的时候才能直接读取。
    private volatile int value;

    public final int get() {
        return value;
    }

    //compareAndSet方法的实现得益于硬件的发展:多条步骤的操作行为可以通过一条指令完成。利用JNI来完成CPU指令的操作
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

  //CAS操作:每次从内存中读取数据然后将此数据和+1后的结果进行CAS操作,如果成功就返回结果,否则重试直到成功为止。
    public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }

}

     CAS存在的问题:

扫描二维码关注公众号,回复: 6109079 查看本文章

        1)ABA问题,内存地址V的值是A,线程one从V中取出了A,此时线程two也从V中取出了A,同时将A修改为B,但是又因为一些原因修改为A。而此时线程one仍看到V中的值为A,认为没有发生变化此为ABA问题。解决ABA问题一种方式是通过版本号(version)。每次执行数据修改时,都需要带上版本号,如:1A,2B,3A。通过比较版本号可知是否有发生过操作,也就解决了ABA问题。

        2)未知的等待时长 因为CAS采取失败重试的策略,所以不确定会发生多少次循环重试。如果在竞争激烈的环境下,其重试次数可能大幅增加。此时效率也就降低了。

未完。。

猜你喜欢

转载自blog.csdn.net/sinat_41144773/article/details/89632464
今日推荐