本文参与「新人创作礼」活动,一起开启掘金创作之路。
1、乐观锁和悲观锁
| 类型 | 概念 |
|---|---|
| 乐观锁 | 认为数据一般情况下不会发生冲突,访问前不会加锁,数据提交更新时检测数据是否冲突,不会产生死锁 |
| 悲观锁 | 认为数据很容易被外界修改,在数据处理前对数据加锁,整个数据处理过程中对数据加锁可以避免多线程同时对数据进行操作 |
2、公平锁和非公平锁
| 类型 | 概念 |
|---|---|
| 公平锁 | 线程获取锁的顺序按照线程请求锁的时间,先来后到,new ReentrantLock(true)就是一个公平锁,公平锁性能开销比非公平锁大 |
| 非公平锁 | 先请求锁的线程不一定先获取到锁,new ReentrantLock(false)就是一个非公平锁,构造函数不指定则默认为非公平锁 |
3、独占锁和非独占锁
根据锁只能被单个线程持有还是可以被多个线程共同持有区分
| 类型 | 概念 |
|---|---|
| 独占锁 | 保证任何时候都只有一个线程可以获取到锁,ReentrantLock以独占式实现,是一种悲观锁 |
| 非独占锁 | 可以被多个线程共同持有,例:ReadWriteLock读写锁允许一个资源同时被多个线程进行读操作,是一种乐观锁 |
4、可重入锁 定义:当一个线程获取一个被其他线程持有的独占锁时,线程被阻塞,当该线程获取自己已经获取到的锁时,如果不被阻塞那么该锁是可重入的; 原理:在内部维护一个线程标示,用来标示该锁目前被哪个线程占用,然后关联一个计数器,开始计数器为0表示没有线程获取,当一个线程获取后计数器值为1,这时其他线程再来获取锁发现不是自己持有那么无法获取资源进而阻塞;但是当获取锁的线程再次获取的时候发现持有锁的线程是自己,那么计数器的值累加1,当计数器的值为0的时候,锁中的线程标示重置为null,这时被阻塞的线程被唤醒来竞争锁;
5、自旋锁 Java中的线程和操作系统中的线程是一一对应的,所以当一个线程获取锁失败后会被切换到内核态而挂起,当锁被释放时又要从用户态切换到内核态唤醒阻塞的线程; 定义:当前线程获取锁时发现锁被其他线程占用,这时不立即阻塞自己,在不放弃cpu使用权的情况下多次尝试获取(默认10次,可以通过-XX:PreBlockSpinsh参数设置尝试次数),当次数用完之后才阻塞自己;