可重入锁与不可重入锁
可重入锁(递归锁)
定义:可以递归调用的锁(当某个线程执行某个方法已经获得该锁,在方法中可以再次获取该锁,并且不会发生死锁(前提时同一个对象或Class))
可重入:某个线程已经获得了某个锁,可以再次获取锁而不会出现死锁。
注意:synchronized和ReentrantLock都时可重入锁。
不可重入锁
定义:不可以递归调用的锁(当某个线程执行某个方法已经获得该锁,在方法中再次获取该锁时,会发生阻塞)
自定义可重入锁
解释:当一个类中有A,B两个方法都要加锁,A方法中要调用B方法。当线程1执行A方法时会同时获取A,B两把所锁,只有线程1执行完A方法并释放掉这两把锁时,其他线程才能获得锁。
package juc.lock.Reentrant;
//自定义可重入锁
public class Lock {
private boolean isLock = false;//判断当前锁状态,
private Thread currentThread = null;//当前线程
private int lockCount = 0;//当前锁的层数
//加锁方法
public synchronized void lock(){
while (isLock && currentThread != Thread.currentThread()){//当第二次加锁时,第二个条件为false
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isLock = true;
currentThread = Thread.currentThread();
lockCount++;
}
//解锁方法
public synchronized void unlock(){
if (isLock && currentThread == Thread.currentThread()){
if (--lockCount==0){
isLock=false;
notify();
}
}
}
}
class Test{
Lock lock = new Lock();//自定义可重入锁
public static void main(String[] args) {
Test test = new Test();
new Thread(()->{
test.eat();
},"A").start();
new Thread(()->{
test.drink();
},"B").start();
}
public void eat(){
try {
lock.lock();
System.out.println("线程"+Thread.currentThread().getName()+"->eat");
Thread.sleep(1000);
drink();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void drink(){
try {
lock.lock();
System.out.println("线程"+Thread.currentThread().getName()+"->drink");
}finally {
lock.unlock();
}
}
}
运行结果:
自定义不可重入锁
解释:当一个类中有多个方法,且这些方法都需要获得并释放锁。但其中的某个方法得到锁之后,其他方法必须等该方法释放锁之后才能有获得锁的机会。
package juc.lock.nonReentrant;
//自定义不可重入锁
public class Lock {
private boolean isLock = false;//判断当前锁状态
public synchronized void lock(){
while (isLock){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isLock = true;
}
public synchronized void unlock(){
if (isLock){
isLock = false;
notify();
}
}
}
class Test{
private Lock lock = new Lock();//自定义不可重入锁
public static void main(String[] args) {
Test test=new Test();
new Thread(()->{
test.eat();
},"A").start();
new Thread(()->{
test.drink();
},"B").start();
}
public void eat(){
try {
lock.lock();
System.out.println("线程"+Thread.currentThread().getName()+"->eat");
Thread.sleep(1000);
drink();//调用drink方法尝试再次获取锁时,由于已经加过锁了,所以isLock为true,因此会一直wait。
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void drink(){
try {
lock.lock();
System.out.println("线程"+Thread.currentThread().getName()+"->drink");
} finally {
lock.unlock();
}
}
}
运行结果: