在并发编程中咱们最经常使用到的两块:一种是基于CAS 机制实现的Atomic类操做,一种是基于AQS实现的同步类实现如经常使用的ReentrantLock/Semaphore/CountDownLatch等;html
CAS:编程
CAS是英文单词Compare and Swap的缩写,翻译过来就是比较并替换。多线程
CAS机制中使用了3个基本操做数:内存地址V,旧的预期值A,要修改的新值B。并发
更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改成B。函数
从思想上来讲,synchronized属于悲观锁,悲观的认为程序中的并发状况严重,因此严防死守,CAS属于乐观锁,乐观地认为程序中的并发状况不那么严重,因此让线程不断去重试更新。ui
CAS的缺点:线程
1) CPU开销过大翻译
在并发量比较高的状况下,若是许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很到的压力。htm
2) 不能保证代码块的原子性blog
CAS机制所保证的知识一个变量的原子性操做,而不能保证整个代码块的原子性。好比须要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。
3) ABA问题
这是CAS机制最大的问题所在。(能够经过版本号解决)
AQS:
它维护了一个volatile int state(表明共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列);
以ReentrantLock为例,state初始化为0,表示未锁定状态。A线程lock()时,会调用tryAcquire()独占该锁并将state+1。此后,其余线程再tryAcquire()时就会失败,直到A线程unlock()到state=0(即释放锁)为止,其它线程才有机会获取该锁。固然,释放锁以前,A线程本身是能够重复获取此锁的(state会累加),这就是可重入的概念。但要注意,获取多少次就要释放多么次,这样才能保证state是能回到零态的。好比lock两次,就必须unlock两次;
再以CountDownLatch以例,任务分为N个子线程去执行,state也初始化为N(注意N要与线程个数一致)。这N个子线程是并行执行的,每一个子线程执行完后countDown()一次,state会CAS减1。等到全部子线程都执行完后(即state=0),会unpark()主调用线程,而后主调用线程就会从await()函数返回,继续后余动做。