首先上一张图
是不是吓一跳,下面我们来一项一项说明各种锁的概念以及使用
1.乐观锁
乐观锁顾名思义就是一种乐观的思想,认为读数据时没有别的线程进行过修改,所以不会上锁,写数据时判断当前与期望的值是否相同,如果相同进行更新(更新期间是要枷锁的,为了保证原子性)
举例:java中的乐观锁---CAS
CAS的使用以及CAS原子操作面临的问题,以及解决方案
CAS的详细内容请参考
多线程常见面试题总结(简单版)_Mr.米斯特儿赵的博客-CSDN博客 第17个回答
2.悲观锁
悲观锁顾名思义就是一种悲观的思想,每次拿数据都会悲观的认为其他线程修改了数据,所以每次读写时都会上锁,其他线程想要读写这个数据时,就会被该线程阻塞 ,直到这个线程释放锁.
举例: java中的悲观锁 synchronized修饰的方法和方法块 比如我们尝试用的hashtable,以及StringBuffer他们的方法都被synchronized修饰,ReentrantLock不仅悲观还重入(也属于重入锁)
3.自旋锁
自旋锁就是在获取锁的时候,如果锁被其他线程获取,该线程就会一直循环等待,一直尝试着去获取锁,直到目标达成。而不像普通的锁那样,如果获取不到锁就进入阻塞
自旋锁的优点: 避免了线程切换的开销,不会使线程进入阻塞的状态,减少了不必要的上下文的切换,执行速度块
自旋锁的缺点: 长时间占用处理器,会白白消耗 处理器资源,却没有干任何事情,性能浪费
所以自旋等待的时间必须有一定的限度 超过限度就挂起 线程
自旋默认的次数: 10次
4.可重入锁(递归锁)
可重入锁使一种技术,任意线程在获取到 锁之后能够再次 获取 该锁而不会被锁阻塞
原理 : 通过组合自定义同步器来实现锁的获取和释放
再次获取锁: 识别获取 锁的线程是否为当前占据锁的线程,如果是,则再次成功获取,获取锁后,进行计数自增
释放锁: 释放锁 进行计数自减
java中的可重入锁:
5.读写锁
读写锁使一种技术,通过ReentrantReadWriteLock类来实现的,为了提高性能,Java提供了读写锁,读的地方使用 读锁,写的地方使用写锁,在没有写锁的情况下,读锁是无阻塞的,多个读锁不互斥,读锁与写锁互斥,这是由jvm来控制的
读锁: 允许线程获取读锁,同时访问一个资源
写锁: 允许一个线程获取 写锁,不允许 同时访问一个资源
如何使用: 1.创建一个读写锁
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
2.获取读锁和释放锁
// 获取读锁rwLock.readLock().lock();// 释放读锁rwLock.readLock().unlock();
3.获取写锁和释放锁
创建一个写锁rwLock.writeLock().lock();// 写锁 释rwLock.writeLock().unlock()
6.公平锁
公平锁使一种思想,多个线程按照顺序来获取锁 ,并发环境中,每个线程会去查看锁的维护队列,如果队列为空,就占有锁,如果队列不为空,就加入等待队列的末尾,按照FIFO原则获取锁
7.非公平锁
非公平锁也是一种思想,线程尝试获取锁,如果获取不到,按照公平锁的方式,多个线程获取锁不是按照 先到先得的顺序.是无序的,有可能后到了先获取到锁
优点: 比公平锁性能高
缺点: 线程 饥饿(某个线程很长一段时间获取不到锁)
举例: synchronized是非公平锁
ReentrantLock通过构造函数指定该锁是公平的还是非公平的,默认是非公平的。
8.共享锁
共享锁是一种思想,可以多个线程获取读锁,以共享的方式持有锁,和乐观锁还有读写锁同义
9.独占锁
独占锁是一种思想,只能有一个线程获取锁,以独有的方式持有锁,悲观锁和互斥锁同义
10.重量级锁
11.轻量级锁
jdk6是加入的一种锁的优化机制,轻量级锁是在没有多线程竞争的情况下使用的CAS操作去消除同步使用的互斥量
上面理解起来很吃力,解析一下,首先是没有竞争,也就是说是单线程 ,两条以上线程,轻量级锁不会生效
12.偏向锁
是JDK6时加入的一种锁优化机制:
在无竞争的情况下把整个同步都消除掉,连CAS操作都不去做了。偏是指偏心,它的意思是这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁一直没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作.
13.分段锁
是一种机制,是不是想到了ConcurrentHashMap了,默认情况下ConcurrentHashMap被细分为16个段(Segment)每次上锁只是锁的每个segment. segment通过继承ReentrntLock来进行加锁,只要保证每个segment是线程安全的,是不是就保证了全局的线程安全.
14.互斥锁
互斥锁和悲观锁还有独占锁同义,某个资源,只能被一个线程访问,其他线程不能访问.
例如上文提到的读写锁中的写锁,写与写之间是互斥的,写与读之间也是互斥的
15.同步锁
与互斥锁同义,字并发执行多个线程时,在同一时间只允许一个线程访问共享数据 synchronized
16.死锁
如线程A持有资源x,线程B持有资源y,线程A等待线程B释放资源
17.synchronized(简单总结)
synchronized是java中的关键字,用来修饰方法,对象实例,属于独占锁,悲观锁,可重入锁,非公平锁
用于实例方法时,锁住的是对象的实例也就是this
用于静态方法上,锁主的是Class类
18.Lock和synchronized的区别
lock 是java中的接口,是可重入锁,悲观锁,独占锁,互斥锁,同步锁
lock 需要手动获取锁和释放锁
lock 是一个接口,synchronized是关键字
synchronized发生异常会自动释放锁,不会导致死锁现象,而lock发生异常如果没有unlock()释放锁,就有可能产生死锁,一般使用lock锁的时候,需要在finally中进行释放锁
lock锁可以使等待的线程响应中断,而synchronized不会,会一直等待下去
19.ReentrantLock 和synchronized的区别
Reentrantlock是java中的类,继承了lock类,是可重入锁,悲观锁,独占锁,互斥锁,同步锁
相同点: 主要解决共享变量如何访问的问题
都是可重入锁,同一线程可以多次获取锁
保证了线程安全的两大特性 可见性 原子性
不同点:
- ReentrantLock 就像手动汽车,需要显示的调用lock和unlock方法,synchronized 隐式获得释放锁。
- ReentrantLock 可响应中断, synchronized 是不可以响应中断的ReentrantLock 为处理锁的不可用性提供了更高的灵活性
- ReentrantLock 是 API 级别的, synchronized 是 JVM 级别的
- ReentrantLock 可以实现公平锁、非公平锁,默认非公平锁,synchronized 是非公平锁,且不可更改。
- ReentrantLock 通过 Condition 可以绑定多个条件