1.公平锁和非公平锁
定义:
公平锁是指多个线程按照申请锁的顺序来获取锁,类似排队打饭,先来后到。
非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。在高并发的情况下,有可能会造成优先级反转或者饥饿现象。
哪些属于:
并发包中ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,默认是非公平锁。
公平锁和非公平锁的区别:
1.公平锁,就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会按照FIFO的规则从队列中取到自己
2.非公平锁比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式。
3.非公平锁的优点在于吞吐量比公平锁大。
4.对于Synchronized而言,也是一种非公平锁
2.可重入锁(递归锁)
定义:
指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁,这样的锁就叫做可重入锁。
哪些属于:
synchronized关键字(隐式锁)、ReentrantLock类(显式锁)
synchronized默认是可重入锁,简单的来说就是:在一个synchronized修饰的方法或代码块的内部调用本类的其他synchronized修饰的方法或代码块时,是永远可以得到锁的。
原理:
每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针。
当执行monitorenter时,如果目标锁对象的计数器为零,那么说明它没有被其他线程所持有,Java虚拟机会将该锁对象的持有线程设置为当前线程,并且将其计数器加1。
在目标锁对象的计数器不为零的情况下,如果锁对象的持有线程是当前线程,那么Java 虚拟机可以将其计数器加1,否则需要等待,直至持有线程释放该锁。
当执行monitorexit时,Java虚拟机则需将锁对象的计数器减1。计数器为零代表锁己被释放。
同步代码块的可重入锁演示,代码:
private static void reEntryM1() {
Object object=new Object();
new Thread(()->{
synchronized(object){
System.out.println(Thread.currentThread().getName()+"----外层调用");
synchronized(object){
System.out.println(Thread.currentThread().getName()+"----中层调用");
synchronized(object){
System.out.println(Thread.currentThread().getName()+"----内层调用");
}
}
}
},"t1").start();
}
结果:
同步方法的可重入锁演示,代码:
private static void reEntryM2() {
Test test = new Test();
new Thread(()->{
test.m1();
},"t1").start();
}
public synchronized void m1(){
System.out.println(Thread.currentThread().getName()+"---- m1 come in");
m2();
System.out.println(Thread.currentThread().getName()+"----m1 end");
}
public synchronized void m2(){
System.out.println(Thread.currentThread().getName()+"----m2 come in");
m3();
System.out.println(Thread.currentThread().getName()+"----m2 end");
}
public synchronized void m3(){
System.out.println(Thread.currentThread().getName()+"----m3 come in");
System.out.println(Thread.currentThread().getName()+"----m3 end");
}
结果:
ReentrantLock类的可重入锁演示,代码:
private static void reEntryM3() {
ReentrantLock reentrantLock = new ReentrantLock();
new Thread(()->{
try {
reentrantLock.lock();
System.out.println(Thread.currentThread().getName()+"----外层调用");
try {
reentrantLock.lock();
System.out.println(Thread.currentThread().getName()+"----中层调用");
try {
reentrantLock.lock();
System.out.println(Thread.currentThread().getName()+"----内层调用");
}finally {
reentrantLock.unlock();
}
}finally {
reentrantLock.unlock();
}
}finally {
reentrantLock.unlock();//加锁几次就要解锁几次,否则其他线程无法获取到该锁的资源
}
},"t1").start();
}
结果:
3.死锁
多个线程在已经抢占到各自锁资源后,继续抢占对方的资源,无法抢到对方的资源就相互等待。