最近在看Java ReentrantLock源代码,但是还是没有完全理解可重入和不可重入的概念。今天我特意整理了这篇文章,让你彻底了解Java重入锁和非重入锁。有需要的朋友可以参考一下。
可重入锁
广义的可重入锁是指可以重复递归调用的锁。锁在外层使用后,仍然可以在内层使用而不会死锁(前提是同一个对象或类)。这种锁被称为重入锁。
我的理解是,一个线程已经获取了某个锁,不需要等待就可以再次获取锁,不会出现死锁(当然不同的线程不能多次获取锁,需要等待)。
简单来说,一个线程获得一个锁,然后它可以再次获得锁,而无需等待,没有死锁。
常见的可重入锁
Synchronized和ReentrantLock是可重入锁。
可重入锁的释放
当同一个线程获得同一个锁时,状态值state将被累加。假设状态累积到2,锁每释放一次就减1。只有当状态值state减少到0时,其他线程才有机会获得锁。也就是说,国零就是已经解锁的标致。
可重入锁示例
公共类ReentrantTest实现Runnable {
@覆盖
公共无效运行(){
get();
}
公共同步void get() {
system . out . println(thread . current thread()。getName());
set();
}
/**
*递归方法
*/
公共同步空集(){
system . out . println(thread . current thread()。getName());
}
/**
*这里只有一个对象锁,就是rt对象的锁。
*当执行rt的get方法时,线程获取rt对象的锁。在get方法中执行set方法时,会再次请求rt对象的锁。因为synchronized是一个可重入的锁,所以它可以被再次获取。循环这个过程。
*假设不是重入锁,请求过程中会有阻塞,导致死锁。
* @param args
*/
公共静态void main(String[] args) {
reentrant test rt=new reentrant test();
//for(;)模拟无限循环
for(;){
新线程(rt)。start();
}
}
}
分析:这里只有一个对象锁,就是rt对象的锁。当执行rt的get方法时,线程获取rt对象的锁。在get方法中执行set方法时,会再次请求rt对象的锁。因为synchronized是一个可重入的锁,所以它可以被再次获取。循环这个过程。如果不是重入锁,请求过程中会有阻塞,导致死锁。
死锁
在多线程中,不同的线程在等待其他线程释放锁,而其他线程由于某种原因没有释放锁。程序运行受阻,无法正常运行或终止。
运行结果
Set()和get()同时输出同一个线程名,也就是说,一个线程执行时,不仅进入了set同步方法,还进入了get同步方法。使用递归同步时没有死锁,证明是可重入的。
可重入锁的实现原理?
每个锁都与一个线程保持器和一个计数器相关联。当计数器为0时,意味着锁没有被任何线程持有,因此任何线程都可能获得锁并调用相应的方法。当线程请求成功时,JVM将记下持有锁的线程,并将计数器设置为1;当其他线程请求锁时,它们必须等待。如果持有锁的线程再次请求锁,它可以再次获得锁,计数器将增加1;当线程退出同步代码块时,计数器将减1。如果计数器为0,锁将被释放。
让我们来分析上面这个可重入锁的例子。
递归调用同步代码块一次,计数器就会变成2。整个递归调用执行完后,先退出内层执行减1,再退出外层执行减1。然后松开锁。
不可重入锁
也就是一个线程已经获取了一个锁,然后不能再获取锁,就会被阻塞。
设计一个不可重入的锁。
公共类锁{
私有布尔值isLocked=false
/**
*锁定
*/
公共同步void锁()引发异常{
while(isLocked){
//当前线程释放锁,放弃CPU,进入等待状态,继续执行15行,直到被唤醒。
wait();
system . out . println(' wait ');
}
isLocked=true
}
/**
*解锁
*/
公共同步void unlock(){
isLocked=false
//唤醒一个等待的线程继续执行
notify();
}
}
测试
公共类测试{
Lock Lock=new Lock();
公共void print()引发异常{
//锁定标志为真
lock . lock();
//释放锁——等待它在第16行被阻塞
doAdd();
lock . unlock();
}
公共void doAdd()引发异常{
lock . lock();
system . out . println(' do add ');
lock . unlock();
}
公共静态void main(String[] args)引发异常{
测试Test=new Test();
test . print();
}
}
结果:虽然这里模拟的是不可重入锁,但实际上是在单线程环境中。当前线程执行print()方法,首先将标志锁定为true,然后释放锁——等待16行内阻塞的14行。在整个过程中,第一次进入锁同步方法,执行完成后,第二次进入锁同步方法,阻塞,等待。这个例子很好地说明了不可重入锁。
这就是本文对Java可重入锁和不可重入锁的全面理解。关于Java可重入锁和不可重入锁的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望你以后能支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。