这里写目录标题
- 1.悲观锁和乐观锁
- 2.悲观锁和乐观锁的场景
- 3.自旋锁和自适应自旋锁
- 4.无锁、偏向锁、轻量级锁、重量级锁
- 5.公平锁和非公平锁
- 6.可重入锁
- 7.排他锁和共享锁
- 8.锁优化技术
1.悲观锁和乐观锁
悲观锁:在修改数据时,一定有别的线程来使用,所以在获取数据的时候会加锁。java中的synchronized和Lock都是悲观锁。
乐观锁:在修改数据时,一定没有别的线程来使用,所以不会添加锁。但是在更新数据的时候,会查看有没有线程修改数据。比如:版本号和CAS原理(无锁算法)。
2.悲观锁和乐观锁的场景
悲观锁:更适合写操作多的场景,因为先加锁可以保证数据的正确。
乐观锁:更适合读写操作多的场景,因为不加锁会让读操作的性能提升。
3.自旋锁和自适应自旋锁
背景:因为线程竞争,会导致线程阻塞或者挂起,但是如果同步资源的锁定时间很短,那么阻塞和挂起的花费的资源就得不偿失。
自旋锁:当竞争的同步转移锁定时间短,就让线程自旋,如果自旋完成后,资源释放了锁,那线程就不用阻塞,直接获取资源,减少了线程的开销。实现原理是CAS。
缺点:占用了处理器的时间,如果锁被占用的时间短还好,如果长就白白浪费了处理器的时间。所以要限定自旋次数(默认是10次,可以使用-XX:PreBlockSpin来更改)没有成功获得锁,就应当挂起线程。
自适应自旋锁:自旋次数不固定,是由上一个在同一个锁上的自旋时间和锁拥有者的状态决定。如果在同一个锁对象上,自旋刚刚获得锁,并且持有锁的线程在运行,那么虚拟机会认为这次自旋也可能成功,那么自旋的时间就会比较长,如果某个锁,自旋没成功获得过,那么可能就会直接省掉自旋,进入阻塞,避免浪费处理器时间。
4.无锁、偏向锁、轻量级锁、重量级锁
这四个锁是专门针对synchronized的,在JDK1.6,对synchronized锁的实现引入了大量的优化,并且synchronized有多种锁状态。级别从低到高依次是:无锁、偏向锁、轻量级锁、重量级锁。锁状态只能升级不能降级。
无锁:就是乐观锁。
偏向锁:当只有一个线程访问加锁的资源,不存在多线程竞争的情况下,那么线程不需要重复获取锁,这时候就会给线程加一个偏向锁(对比Mark Word解决加锁问题,避免CAS操作)
轻量级锁:是指当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。(CAS+自旋)
重量级锁:若当前只有一个等待线程,则该线程通过自旋进行等待。当是当自旋超过一定的次数或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁升级为重量级锁。(将除了拥有锁的线程以外的线程都阻塞)
5.公平锁和非公平锁
公平锁:多个线程按照申请锁的顺序来获取锁。Lock lock=new ReentrantLock(true);默认是非公平锁,设置为true是公平锁。
优点:等待线程不会饿死。
缺点:CPU唤醒线程的开销比非公平锁要大。
非公平锁:多个线程获取锁的顺序并不是按照申请锁的顺序。synchronized和lock都是非公平锁。
优点:减少唤醒线程的开销。
缺点:可能会出现线程饿死或者很久获得不了锁。
6.可重入锁
一个线程如果抢占到了互斥锁的资源,在锁释放之前再去竞争同一把锁的时候,不需要等待,只需要记录重入次数。
7.排他锁和共享锁
排他锁(Exclusive Lock):排他锁是一种独占锁,也称为写锁,当一个事务获取了排他锁后,其他事务无法再获取该数据项的任何锁,包括共享锁和排他锁。排他锁适用于需要修改数据的操作,它确保再事务修改数据时,其他事务无法读取或修改相同的数据,从而保证了数据的一致性。
共享锁(Shared Lock):共享锁是一种共享访问锁,也称为读锁。多个事务可以同时获取相同数据项的共享锁,彼此之间不会互斥。共享锁适用于只读操作,它允许多个事务同时读取相同的数据,提高了并发性能。
8.锁优化技术
锁粗化:将多个同步块的数量减少,并将单个同步块的作用范围扩大,本质上就是将多次上锁、解锁的请求合并为一次同步请求。
锁消除:锁消除是指虚拟机编译器在运行时检测到了共享数据没有竞争的锁,从而将这些锁进行消除。