文章目录
一、公平锁和公平锁的比较
1、什么是公平锁和非公平锁?
a、什么是公平锁:是指多个线程按照申请锁的顺序来获取锁,类似于 队列的先进先出。
b、什么是非公平锁:是指在多线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取到锁,在高并发的情况下,有可能造成优先级反转或者饥饿现象。
2、公平锁和非公平锁区别
a、公平锁:在并发的环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前是第一个,就占有锁,否则就会加入到等待队列中,之后会按照先进先出的规则获取线程。
b、非公平锁:一上来就尝试获取锁,如果获取失败就采用公平锁的规则去获取锁。
3、公平锁和非公平锁的使用
a、ReentrantLock 可以通过构造函数指定公平锁或者非公平锁,默认是非公平锁。
b、synchronized 是非公平锁。
二、可重入锁(又叫递归锁)
1、什么是重入锁?
重入锁:指的是同一线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码;同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。
2、可重入锁的使用:
a、ReentrantLock/synchronized就是一个典型的可重入锁。
3、可重入锁的作用:
a、可重入锁最大的作用就是避免死锁。
4、可重入锁代码演示:
class Phone{
public synchronized void sendSms() throws Exception{
System.out.println(Thread.currentThread().getName()+"\tsendSms");
sendEmail();
}
public synchronized void sendEmail() throws Exception{
System.out.println(Thread.currentThread().getName()+"\tsendEmail");
}
}
/**
* Description:
* 可重入锁(也叫做递归锁)
* 指的是同一先生外层函数获得锁后,内层敌对函数任然能获取该锁的代码
* 在同一线程外外层方法获取锁的时候,在进入内层方法会自动获取锁
**/
public class ReenterLockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
try {
phone.sendSms();
} catch (Exception e) {
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try {
phone.sendSms();
} catch (Exception e) {
e.printStackTrace();
}
},"t2").start();
}
}
运行结果:
三、自旋锁
1、什么是自旋锁?
自旋锁:是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式不断的取获取锁。
2、自旋锁的优缺点
a、优点:自旋锁尽可能的减少线程的阻塞,这对于锁的竞争不激烈,且占用锁时间非常短的代码块来说性能能大幅度的提升,因为自旋的消耗会小于线程阻塞挂起再唤醒的操作的消耗,这些操作会导致线程发生两次上下文切换.
b、缺点:如果锁的竞争激烈,或者持有锁的线程需要长时间占用锁执行同步块,这时候就不适合使用自旋锁了,因为自旋锁在获取锁前一直都是占用 cpu 做无用功,占着茅坑不 拉屎,同时有大量线程在竞争一个锁,会导致获取锁的时间很长,线程自旋的消耗大于线程阻塞挂起操作的消耗,其它需要cpu的线程又不能获取到cpu,造成 cpu 的浪费,所以这种情况下我们要关闭自旋锁。