一、锁的概念
java中的锁就是为了在多线程环境下为保证线程安全的一种手段。
二、锁的分类
以java来说,关于锁的大分类就只有悲观锁与乐观锁,其余说的各种锁毒师基于这两大类的具体细节实现。
三、悲观锁
1.悲观锁的定义:悲观锁认为所有的资源都是不安全的,随时会被其他线程更改。所以在操作资源前要加一把锁防止其他线程访问。
2.java中的悲观锁有哪些:
- synchronized:是一个java中的关键字,底层由jvm虚拟机实现的。通过MONITORENTER(进入)、MONITOREXIT(退出)来实现同步效果。
- 基于AQS实现类:
- AQS:抽象队列同步器,它定义了一个volatile修饰的int类型变量state来控制是否同步。
- ReentrantLock:可重入锁
- ReentrantReadWriteLock:基于ReentrantLock的读写锁,读写、写写互斥,读读不互斥
- CountDownLatch:倒计时器
- CyclicBarrier:循环栅栏
- Semaphore:信号量
四、乐观锁
1.乐观锁的定义:乐观锁认为所有的资源都是安全的,每个线程随资源的操作都是符合预期的,所以它不需要对资源加锁。
2.但是它在操作资源时会用到CAS机制,用来保证锁操作资源未被其他线程更改过。
3.java中的乐观锁有哪些?
Java没有提供可直接使用的乐观锁,不过内置了一些由底层由乐观锁实现的类。例如:java.util.concurrent.atomic下的几个原子类。
如果我们想自己实现乐观锁的话,可以参考上面那些原子类,使用valotile+CAS 的方式实现。
4.CAS:Compare And Swap
它拥有三个关键参数:V:内存中的值 E:期望值 N:新值
- 当期望值和旧值一致时,才会将旧值替换为新值,否则该线程不做任何操作; 当期望值和旧值不一致,就是其他线程对该值进行了修改(使用中),所以 当前线程不能修改该值。
- 在当前线程修改期间,如何保证修改期间原子性: CAS的执行指令是硬件级别的(CPU的指令)lockcmpxchg
- CAS的自旋:多线程下某个线程的CAS操作失败时,会再次尝试循环获取直到成功的现象。 (当预期值与内存中的值不一致时,重新比较,一直重复此过程的效果)
- 自旋出现的问题:ABA问题、循环时间长开销、只能保证一个变量的原子性操作
- ABA问题的解决方案:加一个版本号,每发生一次交换,版本号+1,预期值与旧值一致,并且版本号也一致时,再执行交换
- JAVA中如何实现CAS:
- java.util.Concurrent.Atomic:在此包下,提供了原子类,这些类底层都是CAS
- juc(java.util.Concurrent):JAVA的并发编程(多线程)
5.volatile:
- 实质:就是告诉JVM当前工作内存中的值不可信,需要直接去主存中读取数值。
- 作用:
- 保证可见性
- 防止指令重排