在 Java 并发编程中,volatile、synchronized、CAS 和 AQS 都是用于保证线程安全和同步的机制。
- volatile 是java的关键字,禁止JVM对该变量的操作进行指令重排,保证变量在多线程环境中的内存可见性。每个线程可能会在自己的本地缓存中操作变量,而不是直接操作主内存。这样,如果一个线程修改了一个普通的共享变量,其他线程可能无法及时看到这个修改,导致数据不一致。而通过将变量声明为 volatile,Java 保证所有线程都会直接从主内存读取该变量的最新值。
- synchronized 是java悲观锁的实现,可以加在方法上,或单独使用一个变量作为锁对象,加锁之后其他线程阻塞等待,性能较差。
- CAS 是乐观锁的实现,修改对象前,先备份对象值再进行更新,更新完成尝试写入时,比较当前值与备份的原值是否发生变化,发生变化则不断重试,直到成功为止,通过逻辑上的锁,实现锁的最小粒度,保证更新的原子性。
- AQS 基于CAS,线程A尝试修改变量,首先尝试将锁标识更新为1,此时线程B也尝试获取锁标识,此时A还没更新完,锁标识还是0,在这个过程中,线程A成功将锁标识更新为1,当线程B尝试通过CAS更新锁标识,发现锁标识已经是1,就开始自旋重试,当线程B重复多次自旋都更新失败,会将当前线程挂起,加入AQS的FIFO先进先出阻塞任务队列,此时又进来个线程C,C发现该对象的锁标识为1,则直接加入FIFO队列,当线程A完成更新,释放锁,将锁标识重置为0,此时会唤醒FIFO队列中的线程B和线程C,尽管是先进先出队列,但默认是非公平锁,不是先来的先执行,而是同时竞争,公平锁则是按FIFO顺序依次执行。
AQS的性能较好,JUC中提供的 ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch、CyclicBarrier 等锁,都是基于AQS实现的。