JUC高并发编程
六、多线程锁
6.3)可重入锁
核心问题场景:当一个线程获得当前实例的锁lock,并且进入了方法A,该线程在方法A没有释放该锁的时候,是否可以再次进入使用该锁的方法B?
不可重入锁:在方法A释放锁之前,不可以再次进入方法B
可重入锁:在方法A释放该锁之前,可以再次进入方法B
不可重入锁:
当线程在访问A方法的时候,获取的A方法的锁,在A方法锁释放之前不能够访问其他方法(如方法B)的锁。
不可重入锁模型:{}{}{}{}{}都是独立的访问每一个方法,加锁 - 释放;加锁 - 释放。。。
可重入锁:
当线程在访问A方法的时候,获取A方法的锁,然后访问B方法获取B方法的锁,并计数加1,以此类推可以访问完了以后依次解锁。
可重入锁模型:{{{{}}}} 每次都可访问另一个方法,且加锁计数器加1,完全释放锁为计数器等于0
可重入锁,是指同一个线程可以重入上锁的代码段,不同的线程进入则需要进行阻塞等待。
Java的可重入锁有:reentrantLock(显式的可重入锁)【手动上锁解锁】、synchronized(隐式的可重入锁)【自动上锁解锁】
可重入锁诞生的目的:防止死锁,导致同一个线程不可重入上锁代码段,目的就是让同一个线程可以重新进入上锁代码段
6.3.1)synchronized实现可重入锁
synchronized实现可重入锁代码示例:
//synchronized实现可重入锁代码示例
public class SyncLockDemo {
public static void main(String[] args) {
// synchronized实现可重入锁
Object o = new Object();
new Thread(() -> {
synchronized (o) {
System.out.println(Thread.currentThread().getName() + " 外层");
synchronized (o) {
System.out.println(Thread.currentThread().getName() + " 中层");
synchronized (o) {
System.out.println(Thread.currentThread().getName() + " 内层");
}
}
}
}, "t1").start();
}
}
输出:在外层的锁释放前,仍然可以进入上锁的中层和内层代码块
t1 外层
t1 中层
t1 内层
可重入锁又称递归锁,递归锁代码示例:
public class SyncLockDemo1 {
public synchronized void add() {
add();
}
public static void main(String[] args) {
new SyncLockDemo1().add();
}
}
输出:
Exception in thread "main" java.lang.StackOverflowError
at com.study.sync.SyncLockDemo1.add(SyncLockDemo1.java:12)
6.3.2)Lock 实现可重入锁
Lock实现可重入锁代码示例:
// Lock实现可重入锁代码示例
public class SyncLockDemo2 {
public static void main(String[] args) {
//Lock演示可重入锁
Lock lock = new ReentrantLock();
//创建线程
new Thread(() -> {
try {
//上锁
lock.lock();
System.out.println(Thread.currentThread().getName() + " 外层");
try {
//上锁
lock.lock();
System.out.println(Thread.currentThread().getName() + " 内层");
} finally {
//释放锁
lock.unlock();
}
} finally {
//释放做
lock.unlock();
}
}, "t1").start();
//创建新线程
new Thread(() -> {
lock.lock();
System.out.println("aaaa");
lock.unlock();
}, "aa").start();
}
}
输出:lock 需要手动上锁和解锁,如果不解锁,将会一直卡在该线程中,无法继续执行后面的线程创建操作
t1 外层
t1 内层
aaaa