JAVASE小白学习笔记 简单探索CAS算法原理

简单探索CAS算法原理

  • 1.CAS算法理解
  • 2.以实例说明CAS算法的作用
  • 总结

看了标题后,许多朋友会不禁发出疑问,什么是CAS算法? 简单来说,CAS为Compare and Swap的意思,即比较并交换的算法。


1.CAS算法理解

  • JDK1.5增加了并法包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronize同步锁的一种乐观锁。JDK1.5之前Java语言是靠synchronized关键字来保证同步的,这是一种独占锁(就是有你没我的意思),也是悲观锁。

如一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进行修改时(如更改用户帐户余额),如果采用悲观锁机制,也就意味着整个操作过程中(从操作员读出数据、开始修改直至提交修改结果的全过程),数据库记录始终处于加锁状态,可以想见,如果面对几百上千个并发,这样的情况将导致怎样的后果。乐观锁机制在一定程度上解决了这个问题。

对于CAS的理解,可以简单将CAS理解为一种无锁的算法,CAS中有3个操作数,内存值V,预期值A,以及要修改的新值B。当且仅当预期值A与内存值V相同时,将内存值 V修改为B,否则什么都不做。


2.以实例说明CAS算法的作用

前面我们了解到了i++的原子性问题:i++算法在代码层面只有一步操作,但交给CPU指令进行操作实际上分为3个步骤,即“读–改--写”。而前面我们知道volatile可以保证可见性,但是不能保证原子性。

  • 实际上除了synchronize实现原子性外,CAS算法也可以保证数据变量的原子性。

在java.util.concurrent.atmoic包下提供了一些原子变量。所谓原子变量,就是类的小工具包,支持在单个变量上解除锁的线程安全编程。事实上,此包中的类可将voilatile值,字段和数组元素概念扩展到那些也提供原子条件更新操作的类。

在原子类变量中,如java.util.concurrent.atomic中的AtomicXXX,都使用了这些底层的JVM支持为数字类型的引用类型提供一种高效的CAS操作,而在java.util.concurrent中的大多数类在实现时都直接或间接的使用了这些原子变量类。

  • 与前面的卖票程序一致的代码,这里采用多线程操作多条共享语句(i++)。代码如下,所以会发生多线程安全问题,这里会出现相同的数字。
public class MyRunnable implements Runnable {
     
    //提供共享变量
    static int i=0;

    @Override
    public void run() {
     
        while (true) {
     

            try {
     
                Thread.sleep(100);
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
            //i++不是原子性操作,所以会发生多线程安全问题
            System.out.println(i++);

        }
    }
}

public class MyTest {
     
    public static void main(String[] args) {
     
        MyRunnable myRunnable = new MyRunnable();
        //利用for循环开启10个线程操纵共享资源,与i++语句
        for (int i = 0; i < 10; i++) {
     
            new Thread(myRunnable).start();
        }
    }
}

执行后结果会出现相同的数字:
JAVASE小白学习笔记 简单探索CAS算法原理_第1张图片

  • 这里除过利用sychronized解决原子性问题,还可以使用CAS算法来解决。代码如下:
//在java.util.concurrent.atmoic包下提供了一些原子变量。
// 所谓原子变量,就是类的小工具包,支持在单个变量上解除锁的线程安全编程。
import java.util.concurrent.atomic.AtomicInteger;
public class MyRunnable implements Runnable {
     
       AtomicInteger i= new AtomicInteger(1);
       //提供成员变量的get方法
      public AtomicInteger getI() {
     
        return i;
      }
    @Override
    public void run() {
     
        while (true) {
     
            try {
     
                Thread.sleep(100);
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
            System.out.println(i.getAndIncrement());


        }
    }
}

public class MyTest {
     
    public static void main(String[] args) {
     
        MyRunnable myRunnable = new MyRunnable();
        for (int i = 0; i < 10; i++) {
     
            new Thread(myRunnable).start();

        }
    }
}
  • 输出的结果没有相等的数字,即解决多线程安全问题,如下图。

JAVASE小白学习笔记 简单探索CAS算法原理_第2张图片

  • AtomicInteger.GetAndincrement 的实现用了乐观锁技术,调用了类sun.misc.Unsafe库里面的 CAS算法,用CPU指令来实现无锁自增。所以 AtomicInteger.GetAndincrement 的自增比用synchronized的锁效率倍增。

总结

关于CAS算法的介绍,到这里就结束了。对于CAS算法的理解这部分大家要对其处理的思想要弄清楚,面试中谈及多线程安全问题时也能与面试官聊聊CAS算法的理解,会很加分呦。

JAVASE小白学习笔记 简单探索CAS算法原理_第3张图片

你可能感兴趣的:(JAVASE,多线程,java)