外贸商城网站建设,全景网站制作教程,创意设计作品赏析,英语网站都可以做哪些内容可重入锁#xff1a;ReentrantLock 在学JUC的时候#xff0c;听到可重入锁这个词#xff0c;不理解它的概念#xff0c;网上搜索一番#xff0c;还是有点迷糊#xff0c;所以自己再来做一下笔记#xff0c;理一理思路。
一、锁是什么#xff1f;
我们这里提到的锁ReentrantLock 在学JUC的时候听到可重入锁这个词不理解它的概念网上搜索一番还是有点迷糊所以自己再来做一下笔记理一理思路。
一、锁是什么
我们这里提到的锁是指把所需要的代码块资源或数据锁上在操作访问他们的时候只允许一个线程去做操作。最终结果是为了保证cpu计算结果的正确性。
二、可重入锁与不可重入锁的区别
1、不可重入锁
只判断这个锁有没有被锁上只要被锁上申请锁的线程都会被要求等待。实现简单2、可重入锁
不仅判断锁有没有被锁上还会判断锁是哪个线程锁上的当就是当前锁上的时候那么他依旧可以再次访问临界资源并把加锁次数加一。设计了加锁次数以实现在解锁的时候可以确保所有加锁的过程都解锁了其他线程才能访问。不然没有加锁的参考值也就不知道什么时候解锁解锁多少次才能保证本线程已经访问完临界资源了可以唤醒其他线程访问了。实现相对复杂。
3、结论
这个重入的概念就是拿到锁的线程能不能多次以不同的方式访问临界资源而不出现死锁等相关问题。经典之处就在于判断了需要使用锁的线程是否为加锁的线程。如果是则拥有重chong入的能力。
三、下面使用代码来说明
1、不可重入锁的理解
public class Test{Lock lock new Lock();public void methodA(){lock.lock();...........;methodB();...........;lock.unlock();}public void methodB(){lock.lock();...........;lock.unlock();}
}当A方法获取lock锁去锁住一段需要做原子性操作的B方法时如果这段B方法又需要加锁去做原子性操作那么A方法就必定要与B方法出现死锁。这种会出现问题的重入一把锁的情况叫不可重入锁。
A方法需要等B方法执行完才能解锁但是B方法想执行完代码又必须要lock锁来加锁。A的锁未解锁前其他代码块无法使用此锁来加锁。这是由这个不可重入锁决定的。
2、不可重入锁的加锁与解锁实现
public class Lock{private boolean isLocked false;public synchronized void lock() throws InterruptedException{while(isLocked){ wait();}isLocked true;}public synchronized void unlock(){isLocked false;notify();}
}那么平时我们又有需要重入一把锁的需求比如A方法是个原子性操作但它有需要调用B方法的原子性操作他们还争抢的是同一个临界资源因此需要同一把锁来加锁
ps争抢同一临界资源的实质就是对同一把锁的争抢
针对此情况就有了可重入锁的概念。
3、可重入锁的实现
public class Lock{boolean isLocked false;Thread lockedBy null;//临界资源被哪个线程锁住了int lockedCount 0;public synchronized void lock()throws InterruptedException{Thread thread Thread.currentThread();//加锁时先获取当前线程。识别谁需要锁while(isLocked lockedBy ! thread){wait();}isLocked true;lockedCount;lockedBy thread;}public synchronized void unlock(){if(Thread.currentThread() this.lockedBy){lockedCount--;if(lockedCount 0){isLocked false;notify();}}}
}现在我们来理解这段代码先看加锁
3.1、lock isLocked锁的状态。lockedBy临界资源被哪个线程锁住了。Thread thread Thread.currentThread(); 加锁时先获取当前线程识别谁需要锁**while 判断当临界资源已被锁上但当前请求锁的线程又不是之前锁上临界资源的线程。那么当前请求锁的线程需要等待。**
while(isLocked lockedBy ! thread){wait();
}注意上面是个while并且是个wait因此当线程请求不到锁的时候就wait了。
不满足while判断条件的有3种情况
当前锁没有线程使用即 isLocked false。当前锁有线程使用 isLocked true当前请求锁的线程就是现在正在使用锁的线程 lockedBy thread。当前锁没有线程使用当前请求锁的线程就是现在正在使用锁的线程。不可能出现“当前锁莫瑶线程使用 isLocked false” 与 请求锁的线程就是现在正在用锁的线程 isLocked true两者之间是矛盾的
在while条件不满足时那么当前线程可以加锁
isLocked true;
lockedCount;
lockedBy thread;当前请求锁的线程先把锁加上然后把上锁次数1然后把自己本线程赋值给lockedBy以说明当前谁用了这把锁方便之后重入的时候做while判断。
3.2、unlock()
再来看解锁
public synchronized void unlock(){if(Thread.currentThread() this.lockedBy){lockedCount--;if(lockedCount 0){isLocked false;notify();}}
}首先看看要求解锁的线程是不是当前正在使用锁的线程。不是则什么也不做。这个判断使为了保证当前要解锁的线程必须也是加锁的线程谁加的谁来解。否则其他线程也能随意的执行unlock代码就能解锁那这样相当于谁都有一把钥匙了加锁也失去了意义 如果解锁的就是加锁的线程。 那么把加锁次数减一。 然后在判断加锁次数有没有变为0。 变为 0 说明这个锁已经完全解锁了。 锁状态标志 islocked 就可以复位为 false了。 并且随机唤醒某个被 wait() 等待的线程 notify 这就是重入锁的设计。
再次回顾上文所述的
4、可重入锁和不可重入锁的区别
不可重入锁只判断这个锁有没有被锁上只要被锁上申请锁的线程都会被要求等待。实现简单
可重入锁不仅判断锁有没有被锁上还会判断锁是谁锁上的当就是自己锁上的时候那么他依旧可以再次访问临界资源并把加锁次数加一。
设计了加锁次数以在解锁的时候可以确保所有加锁的过程都解锁了其他线程才能访问。不然没有加锁的参考值也就不知道什么时候解锁解锁多少次才能保证本线程已经访问完临界资源了可以唤醒其他线程访问了。实现相对复杂。
重入指拿到锁的线程能不能多次以不同的方式访问临界资源而不出现死锁等相关问题。经典之处在于判断了需要使用锁的线程是否为加锁的线程。如果是则拥有重入的能力。
怎么样现在是不是理解更清晰了
参考原文https://blog.csdn.net/qq_29519041/article/details/86583945